解析获取的方式有如下几种:

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();
    }
}

这种方式在类型已经注册的情况下使用时没问题的,能够获取到注册类型的实例对象,但是如果类型没有经过注册,直接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();
    }
}

我们可以使用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时,将会以哪个构造方法为准呢?答案是——尽可能最多参数,下面我们以实例来分析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
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 { getset; }
}
 
//构造方法参数类型
class Class2
{
    public int Id { getset; }
}
 
//构造方法参数类型
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参数给上默认值,那么最后选择的构造方法将会是这个构造方法。

1
2
3
4
5
6
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的用法,将在后续博文中进行说明)。

1
2
3
4
5
6
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时传入了一个NamedParameter,NamedParameter表示按名字匹配参数,上面的代码表示,为参数名为guid的构造参数传入了Guid.NewGuid值。这段代码最后执行的是第四个构造方法。因为第四个构造方法是能够匹配的最多参数的构造方法。

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; }
}

IoC容器Autofac正篇之解析获取(六)的更多相关文章

  1. IoC容器Autofac正篇之解析获取(五)

    解析获取的方式有如下几种: Resolve class Program { static void Main(string[] args) { var builder = new ContainerB ...

  2. IoC容器Autofac正篇之依赖注入(六)

    依赖注入,这个专业词我们可以分为两个部分来理解: 依赖,也就是UML中描述事物之间关系的依赖关系,依赖关系描述了事物A在某些情况下会使用到事物B,事物B的变化会影响到事物A: 注入,医生通过针头将药物 ...

  3. IoC容器Autofac正篇之类型注册(四)

    Autofac类型注册 类型注册简单的从字面去理解就可以了,不必复杂化,只是注册的手段比较丰富. (一)类型/泛型注册 builder.RegisterType<Class1>(); 这种 ...

  4. IoC容器Autofac正篇之简单实例

    先上一段代码. namespace ConsoleApplication3 { class Program { static void Main(string[] args) { ContainerB ...

  5. IoC容器Autofac正篇之依赖注入(七)

    依赖注入,这个专业词我们可以分为两个部分来理解: 依赖,也就是UML中描述事物之间关系的依赖关系,依赖关系描述了事物A在某些情况下会使用到事物B,事物B的变化会影响到事物A: 注入,医生通过针头将药物 ...

  6. IoC容器Autofac正篇之类型注册(五)

    Autofac类型注册 类型注册简单的从字面去理解就可以了,不必复杂化,只是注册的手段比较丰富. (一)类型/泛型注册 builder.RegisterType<Class1>(); 这种 ...

  7. IoC容器Autofac正篇之简单实例(四)

    先上一段代码. namespace ConsoleApplication3 { class Program { static void Main(string[] args) { ContainerB ...

  8. IoC容器Autofac正篇之类型关联(服务暴露)(七)

    类型关联 类型关联就是将类挂载到接口(一个或多个)上去,以方便外部以统一的方式进行调用(看下例). 一.As关联 我们在进行手动关联时,基本都是使用As进行关联的. class Program { s ...

  9. IoC容器Autofac正篇之类型关联(服务暴露)(八)

    类型关联  类型关联就是将类挂载到接口(一个或多个)上去,以方便外部以统一的方式进行调用(看下例). 一.As关联 我们在进行手动关联时,基本都是使用As进行关联的. 1 2 3 4 5 6 7 8 ...

随机推荐

  1. Memcached内存存储

    早就听说过Memcached独特的内存管理方式,写着篇文章的目的就是了解Memcached的内存管理,学习其源代码. 1.什么是Slab Allocator memcached默认情况下采用了名为Sl ...

  2. 【转】spring管理属性配置文件properties——使用PropertiesFactoryBean|spring管理属性配置文件properties——使用PropertyPlaceholderConfigurer

     spring管理属性配置文件properties--使用PropertiesFactoryBean 对于属性配置,一般采用的是键值对的形式,如:key=value属性配置文件一般使用的是XXX.pr ...

  3. 下载、安装jdk8(Windows下)并配置变量环境

    一.官网下载地址:http://www.oracle.com/technetwork/java/javase/downloads/index-jsp-138363.html 点击下图中的downloa ...

  4. 淘淘商城_day11_课堂笔记

    今日大纲 发布前的准备 实施发布 一部分是由我来发布 一部分是由你们来发布 讲解分布式部署架构 测试 功能测试 压力测试 项目实战的准备以及分组 分组 抽取功能 讲解所需要开发的功能 项目部署上线流程 ...

  5. 复习i++和++j

    一,新建一个Default.aspx页面 在Default.aspx.cs

  6. sublime text2教程

    代码编辑器或者文本编辑器,对于程序员来说,就像剑与战士一样,谁都想拥有一把可以随心驾驭且锋利无比的宝剑,而每一位程序员,同样会去追求最适合自己的强大.灵活的编辑器,相信你和我一样,都不会例外. 我用过 ...

  7. 图的连通性:有向图强连通分量-Tarjan算法

    参考资料:http://blog.csdn.net/lezg_bkbj/article/details/11538359 上面的资料,把强连通讲的很好很清楚,值得学习. 在一个有向图G中,若两顶点间至 ...

  8. Java IO 过滤流 BufferedInput/OutputStream

    Java IO 过滤流 BufferedInput/OutputStream @author ixenos 概念 BufferedInput/OutputStream是实现缓存的过滤流,他们分别是Fi ...

  9. 使用UGUI实现拖拽功能(拼图小游戏)

    实现方式 1.引入UGUI自带的事件系统 UnityEngine.EventSystems 2.为我们的类添加接口 IBeginDragHandler, IDragHandler, IEndDragH ...

  10. 核心梳理——消息处理的骨架流程——ESFramework 4.0 进阶(02)

    在ESFramework 4.0 概述一文中,我们提到ESFramework.dll作为通信框架的核心,定义了消息处理的骨架流程,本文我们来详细剖析这个流程以及该骨架中所涉及的各个组件.ESFrame ...