前言

Autofac是一套高效的依赖注入框架。

Autofac官方网站:http://autofac.org/

Autofac在Github上的开源项目:https://github.com/autofac/Autofac

Autofac安装:通过VS的Nuget可以很方便的获取。

 

解析获取方式

Resolve

class Program
{
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<Class_1>(); //如果注释掉这句,下面Resolve时将会抛出异常 IContainer container = builder.Build();
Class_1 clas1 = container.Resolve<Class_1>();
Console.WriteLine(clas1.Id); Console.Write("Press any key to continue...");
Console.ReadKey();
}
}

class Class_1
{
public Guid Id { get; set; } public Class_1()
{
Id = Guid.NewGuid();
}
}

这种方式在上一篇 Autofac全面解析系列(版本:3.5) – [使用篇(推荐篇):1.类型注册] 的简单示例中有使用到,这种方式在类型已经注册的情况下使用时没问题的,能够获取到注册类型的实例对象,但是如果类型没有经过注册,直接Resolve解析获取,便会抛出异常。

 

ResolveOptional

class Program
{
static void Main(string[] args)
{
var builder = new ContainerBuilder();
//builder.RegisterType<Class_1>(); //这里注释掉类型注册的代码 IContainer container = builder.Build();
Class_1 clas1 = container.ResolveOptional<Class_1>();
Console.WriteLine(clas1 == null ? "null" : clas1.Id.ToString()); //这里将会输出null Console.Write("Press any key to continue...");
Console.ReadKey();
}
}

使用Resolve时,如果类型没有经过注册,则会抛出异常,有时我们并不希望程序因此而抛出异常,我们可以使用ResolveOptional进行解析获取,当类型没有经过注册时,ResolveOptional方法将会返回null作为结果。

 

TryResolve

class Program
{
static void Main(string[] args)
{
var builder = new ContainerBuilder();
//builder.RegisterType<Class_1>(); //这里注释掉类型注册的代码 IContainer container = builder.Build();
Class_1 clas1 = null;
if (container.TryResolve<Class_1>(out clas1))
{
Console.WriteLine(clas1.Id);
}
else
{//这里将会被执行
Console.WriteLine("null");
} Console.Write("Press any key to continue...");
Console.ReadKey();
}
}

这种方式相信大家并不陌生,这种方式与我们常用的Int32.TryParse相同。使用out参数,并且返回一个bool类型表示是否成功获取到类型实例。

 

其他相关内容

Resolve对象构造方法选择原则

当我们注册的类型拥有多个构造方法,那么在Resolve时,将会以哪个构造方法为准呢?答案是——尽可能最多参数,下面我们以实例来分析:

class ConstructorClass
{
private Class1 _clas1;
private Class2 _clas2;
private Class3 _clas3 = null; public ConstructorClass()
{
_clas1 = null;
_clas2 = new Class2 { Id = -1 };
} public ConstructorClass(Class1 clas1, Class2 clas2)
{
_clas1 = clas1;
_clas2 = clas2;
} public ConstructorClass(Class2 clas2, Class3 clas3)
{
_clas2 = clas2;
_clas3 = clas3;
} public ConstructorClass(Class2 clas2, Class3 clas3, Guid guid)
{
_clas1 = new Class1 {Id = guid};
_clas2 = clas2;
_clas3 = clas3;
} public ConstructorClass(Class1 clas1, Class2 clas2, Class3 clas3)
{
_clas1 = clas1;
_clas2 = clas2;
_clas3 = clas3;
} public override string ToString()
{
return string.Format(
"{{Class1.Id: {0}, Class2.Id: {1}, Class3: {2}}}",
_clas1 == null ? "null" : _clas1.Id.ToString(),
_clas2 == null ? "null" : _clas2.Id.ToString(),
_clas3 == null ? "null" : "not null");
}
}

class Class1
{
public Guid Id { get; set; }
} class Class2
{
public int Id { get; set; }
} class Class3
{ }

//感谢 @就是要说不 的反馈纠正,代码已修正
//主程序
class Program
{
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<ConstructorClass>();
builder.RegisterType<Class2>();
builder.RegisterType<Class3>();
var container = builder.Build();
var obj = container.Resolve<ConstructorClass>();
Console.WriteLine(obj);
Console.Write("Press any key to continue...");
Console.ReadKey();
}
} //构造方法测试类
class ConstructorClass
{
private Class1 _clas1;
private Class2 _clas2;
private Class3 _clas3 = null; public ConstructorClass()
{
_clas1 = null; _clas2 = new Class2 { Id = -1 };
} public ConstructorClass(Class1 clas1, Class2 clas2)
{
_clas1 = clas1; _clas2 = clas2;
} public ConstructorClass(Class2 clas2, Class3 clas3)
{
_clas2 = clas2; _clas3 = clas3;
} public ConstructorClass(Class2 clas2, Class3 clas3, Guid guid)
{
_clas1 = new Class1 { Id = guid }; _clas2 = clas2; _clas3 = clas3;
} public ConstructorClass(Class1 clas1, Class2 clas2, Class3 clas3)
{
_clas1 = clas1; _clas2 = clas2; _clas3 = clas3;
} public override string ToString()
{
return string.Format(
"{{Class1.Id: {0}, Class2.Id: {1}, Class3: {2}}}",
_clas1 == null ? "null" : _clas1.Id.ToString(),
_clas2 == null ? "null" : _clas2.Id.ToString(),
_clas3 == null ? "null" : "not null");
}
} //构造方法参数类型
class Class1
{
public Guid Id { get; set; }
} //构造方法参数类型
class Class2
{
public int Id { get; set; }
} //构造方法参数类型
class Class3
{ }

上面的代码,最终输出结果为 {Class1.Id: null, Class2.Id: 0, Class3: not null} ,最终执行的是第三个构造方法(参数为 Class2, Class3 的)。

根据结果,我们再来理解一下之前说的”尽可能最多参数“,按照字面上里说明”最多参数“,那么理应执行的是最后一个构造方法或倒数第二个构造方法,但是为什么却是第三个,这也就是为什么我要加“尽可能”三字了。

先抛开为什么执行的第三个构造方法,我们还是会有疑问”如果执行的是第三个构造方法,那么Class2和Class3参数分别赋的是什么值?值又是从哪儿来?“,这里就涉及到了后面会讲到的构造注入。我们可以看到,在进行类型注册时,我们是对Class2和Class3进行了注册的,而ConstructorClass又是通过Autofac进行获取的,所以Class2和Class3参数的值是由Autofac进行初始化赋值的,Class2和Class3没有自定义构造方法,所以调用的是默认的空构造方法。

在知道Class2和Class3参数的初始化与赋值缘由后,我们再来看看之前的那个问题,为什么会执行第三个构造方法,其实现在就好明白了,因为最后两个的构造方法,一个需要额外的Guid类型参数,另一个需要Class1类型参数,而这两个类型又没有经过注册,如果调用这两个构造方法,那么Auotofac将不知道应该赋何值给这两个参数,所以Autofac最终选择了第三个构造方法。

这里我们还需要注意一点,如果倒数第二个构造方法的Guid参数给上默认值,那么最后选择的构造方法将会是这个构造方法。让我们再次想想尽可能最多参数这句话就明白了:

public ConstructorClass(Class2 clas2, Class3 clas3, Guid guid = default(Guid))
{
_clas1 = new Class1 { Id = guid };
_clas2 = clas2;
_clas3 = clas3;
}

如果在上面改造了倒数第二个构造方法的基础上继续改造最后一个构造方法,将Class1参数也默认赋值为null,那么最后在Resolve获取ConstructorClass实例时,将会抛出异常。因为在尽可能最多的原则上,出现了两个最多参数的构造方法,Autofac不知道应该选择哪个进行执行。异常信息告诉我们可以使用UsingConstructor来解决这个问题(关于UsingConstructor的用法,将在后续博文中进行说明)。

public ConstructorClass(Class2 clas2, Class3 clas3, Class1 clas1 = null)
{
_clas1 = clas1;
_clas2 = clas2;
_clas3 = clas3;
}

 

解析获取传参

我们在上一节明白了Autofac在Resolve时对构造方法选择的原则,尽可能最多的参数中的参数,可以是已经注册的类型,或是赋给默认值,除了这两种方式,还有一种方式是在Resolve时指定参数。

在上一节中,没有添加默认值的情况下,最后执行的是第三个构造方法。我们可以通过在Resolve时传参来选择更多参数的构造方法:

var obj = container.Resolve<ConstructorClass>(new NamedParameter("guid", Guid.NewGuid()));
//点击查看上一节完整代码

这里仅仅只修改这Resolve的这一句代码,其他代码不变。在Resolve时传入了一个NamedParameter,NamedParameter表示按名字匹配参数,上面的代码表示,为参数名为guid的构造参数传入了Guid.NewGuid值。

这段代码最后执行的是第四个构造方法。因为第四个构造方法是能够匹配的最多参数的构造方法(前两个参数类型已注册到Autofac中,最后一个参数由Resolve时传入的NamedParameter传入)。

Resolve的方法签名为:Resolve<T>(this IComponmentContext context, params Parameter[] parameters)

第一个参数也就是我们使用的container,我们主要关注第二个参数——一个可变的Parameter数组,Parameter是一个抽象类,其中NamedParameter为Parameter的一个子类,除了NamedParameter,还有以下几种子类拱Resolve时使用:

参数类型

参数说明

NamedParameter

根据名称进行匹配

PositionalParameter

根据索引进行匹配,注意:起始索引为0

TypedParameter

根据类型进行匹配,注意:传入多个相同类型的TypedParameter,所有该类型的参数都将采用第一个TypedParameter的值

ResolvedParameter

接收两个Func参数,两个Func签名都接收两个相同的参数ParameterInfo和IComponmentContext,第一个参数为参数的信息(常使用放射的朋友应该熟悉),第二个参数还是当做IContainer使用就好了。第一个Func的返回值为bool,表明当前这个ResolvedParameter是否使用当前匹配到的参数,如果返回true,则会执行第二个Func;第二个Func返回一个object对象,用于填充构造参数值。

 

下面有一个这些Parameter使用的示例供参考:

class Program
{
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<ParameterClass>(); var container = builder.Build();
container.Resolve<ParameterClass>(
new NamedParameter("value", "namedParameter"), //匹配名字为value的参数
new TypedParameter(typeof (int), 1), //匹配类型为int的参数
new PositionalParameter(4, "positionalParameter"), //匹配第五个参数(注意,索引位置从0开始)
new TypedParameter(typeof (int), -1), //这个将被抛弃,因为前面已经有一个类型为int的TypedParameter
new ResolvedParameter(
//第一个Func参数用于返回参数是否符合要求,这里要求参数是类,且命名空间不是System开头,所以第四个参数将会匹配上
(pi, cc) => pi.ParameterType.IsClass && !pi.ParameterType.Namespace.StartsWith("System"),
//第二个Func参数在第一个Func执行结果为true时执行,用于给参数赋值,也就是第四个参数的值为这个Func的执行结果
(pi, cc) => new Temp {Name = "resolveParameter"})
);
// 最后的输出结果为: {x:1, y:1, value:'namedParameter', temp.Name:'resolveParameter', obj:'positionalParameter'} Console.Write("Press any key to continue...");
Console.ReadKey();
}
} class ParameterClass
{
public ParameterClass(int x, int y, string value, Temp temp, object obj)
{
Console.WriteLine("{{x:{0}, y:{1}, value:'{2}', temp.Name:'{3}', obj:'{4}'}}", x, y, value, temp.Name, obj);
}
} class Temp
{
public string Name { get; set; }
}

class ParameterClass
{
public ParameterClass(int x, int y, string value, Temp temp, object obj)
{
Console.WriteLine("{{x:{0}, y:{1}, value:'{2}', temp.Name:'{3}', obj:'{4}'}}", x, y, value, temp.Name, obj);
}
}

class Temp
{
public string Name { get; set; }
}

 

尾述

本篇博文主要讲述Autofac中比较常用也比较好用的解析获取方式,并没有把所有的解析方式都讲述出来。

本篇博文的重点实际在于理解构造方法的优先原则,解析获取的方式相对简单易用,而获取传参在实际的编码中应用较少,这点在现在还看不出来,因为当前还没有讲到Autofac在编程过程中的实际用法。后续博文将会慢慢道明,请大家继续关注!

Autofac全面解析系列(版本:3.5) – [使用篇(推荐篇):2.解析获取]的更多相关文章

  1. ABP使用及框架解析系列 - [Unit of Work part.1-概念及使用]

    前言 ABP ABP是“ASP.NET Boilerplate Project”的简称. ABP的官方网站:http://www.aspnetboilerplate.com ABP在Github上的开 ...

  2. java基础解析系列(四)---LinkedHashMap的原理及LRU算法的实现

    java基础解析系列(四)---LinkedHashMap的原理及LRU算法的实现 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析 ...

  3. java基础解析系列(五)---HashMap并发下的问题以及HashTable和CurrentHashMap的区别

    java基础解析系列(五)---HashMap并发下的问题以及HashTable和CurrentHashMap的区别 目录 java基础解析系列(一)---String.StringBuffer.St ...

  4. java基础解析系列(六)---深入注解原理及使用

    java基础解析系列(六)---注解原理及使用 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析系列(二)---Integer ja ...

  5. java基础解析系列(七)---ThreadLocal原理分析

    java基础解析系列(七)---ThreadLocal原理分析 目录 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析系列(二)-- ...

  6. java基础解析系列(八)---fail-fast机制及CopyOnWriteArrayList的原理

    fail-fast机制及CopyOnWriteArrayList的原理 目录 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析系列( ...

  7. java基础解析系列(九)---String不可变性分析

    java基础解析系列(九)---String不可变性分析 目录 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析系列(二)---In ...

  8. java基础解析系列(十)---ArrayList和LinkedList源码及使用分析

    java基础解析系列(十)---ArrayList和LinkedList源码及使用分析 目录 java基础解析系列(一)---String.StringBuffer.StringBuilder jav ...

  9. java基础解析系列(十一)---equals、==和hashcode方法

    java基础解析系列(十一)---equals.==和hashcode方法 目录 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析系 ...

  10. java基础解析系列(六)---注解原理及使用

    java基础解析系列(六)---注解原理及使用 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析系列(二)---Integer缓存及 ...

随机推荐

  1. jQuery的ajax 方法提交多个对象数组问题 C# traditional $.param

    当用$.ajax()向后台提交参数时,如果参数中数组的话一般在后台会用List<T>接收;但老是不成功如下面代码 "}]; "}]; function addUser( ...

  2. Linux设备驱动剖析之Input(四)

    static void input_pass_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) ...

  3. How to Debug Enterprise Portal Code in Dynamics AX 2009

    转载 To set up debugging for pages1. Log into the server that is running the AOS.2. Open the Microsoft ...

  4. 使用jQuery开发一个带有密码强度检验的超酷注册页面

    在今天的jQuery教程中,我们将介绍如何使用jQuery和其它相关的插件来生成一个漂亮的带有密码强度检验的注册页面,希望大家喜欢! 相关的插件和类库 complexify - 一个密码强度检验jQu ...

  5. java.lang.NullPointerException

    你妹的这是什么错误啊? Errors occurred during the build. Errors running builder 'Android Resource Manager' on p ...

  6. JAVA字节码解析

    Java字节码指令 Java 字节码指令及javap 使用说明 ### java字节码指令列表 字节码 助记符 指令含义 0x00 nop 什么都不做 0x01 aconst_null 将null推送 ...

  7. 【开源EFW框架】框架中自定义控件GridBoxCard使用实例说明

    回<[开源]EFW框架系列文章索引>        EFW框架源代码下载V1.3:http://pan.baidu.com/s/1c0dADO0 EFW框架实例源代码下载:http://p ...

  8. PowerShell 启动应用程序【转】

    当你在PowerShell中,启动带参数启动可执行应用程序时,可能会碰到参数解析的错误.最好的方式是使用命令 Start-Process,该命令有两个优点: 程序的路径和程序参数分开,可以使用-Fil ...

  9. 在 VS 中嵌套文件

    效果如下: 用到扩展工具:NestIn 可以通过 VS->工具->扩展管理器->联机库 搜索安装. In WPF: How to create resource dictionary ...

  10. JavaScript富应用MVC MVVM框架

    对框架的挑选 Ember.js.Backbone.js.Knockout.js.Spine.js.Batman.js , Angular.js 1. 轻量级的应用选择哪一个会比较好?2. 那一个比较简 ...