zoukankan      html  css  js  c++  java
  • Autofac

    从容器中的可用服务中, 选取一个构造函数来创造对象, 这个过程就是自动装配.

    一、选择构造函数

    默认情况下, autofac会使用无参构造函数, 去创建对象. 我将Person类稍微修改了下.

    public interface IPerson
    {
        void Self();
    }
    
    public class Person : IPerson
    {
        IAnimal adopt;
    
        public string Name { get; set; }
    
        public int Age { get; set; }
    
        public Person()
        {
            Console.WriteLine("无参构造函数");
        }
    
        public Person(IAnimal MyPerson)
        {
            Console.WriteLine("一个参数构造函数");
            adopt = MyPerson;
        }
    
        public Person(string name, int age)
        {
            Console.WriteLine("两个参数构造函数");
            this.Name = name;
            this.Age = age;
        }
    
        public void Self()
        {
            Console.WriteLine("我叫{0}, 今年{1}岁了!", this.Name, this.Age);
        }
    
        public void Say()
        {
            Console.WriteLine("我领养了一只小动物");
            adopt.Say();
        }
    }

    但是也可以通过传入参数的方式, 去自动选择使用哪一个构造函数. 还可以在注册的时候就指定使用哪一个构造函数.

    builder.RegisterType<Person>();
    
    //-------------------------------------------------
    var person = container.Resolve<Person>();
    person.Self();
    
    var personA = container.Resolve(typeof(Person), new NamedParameter("name", "elvin"), new NamedParameter("age", 18)) as Person;
    personA.Self();

    这种方式, 就是通过传参来控制调用哪一个构造函数, 其内部是通过反射的方式去实现的.

    如果使用UsingConstructor指定了要使用的构造函数, 就不能使用上面的无参方式去实现了, 会报错的.

    builder.RegisterType<Person>().UsingConstructor(typeof(string), typeof(int));
    //-------------------------------------------------
    //var person = container.Resolve<Person>(); 这种方式就会报错
    //person.Self();
    
    var personA = container.Resolve(typeof(Person), new NamedParameter("name", "elvin"), new NamedParameter("age", 18)) as Person;
    personA.Self();

    有图有真相哦.

    二、额外的构造函数参数

    添加构造函数, 有两个地方可以添加, 一个是在注册的时候添加, 另一个是Resolve的时候添加, 就如同上面这个例子中的personA一样的.

    那下面就来说一说注册的时候添加吧.

    builder.RegisterType<Person>().WithParameters(new NamedParameter[] { new NamedParameter("name", "sniper"), new NamedParameter("age", 20) });
    
    //-------------------------------------------------
    var person = container.Resolve<Person>(); 
    person.Self();
    
    var personA = container.Resolve(typeof(Person), new NamedParameter("name", "elvin"), new NamedParameter("age", 18)) as Person;
    personA.Self();

    这个时候, 我发现, 无参的写法和有参的写法, 都不会报错, 而且, 在创建实例的时候, 都是调用的两个参数的构造函数

    如果这个时候, 我使用一个参数的方式去写

    var personB = container.Resolve(typeof(Person), new NamedParameter("MyPerson", new Dog() { Name = "小花" })) as Person;
    personB.Self();

    这个时候, 会发现, autofac完全没有理我, 还是用的之前约定的那个构造函数. 真调皮.

    这种在注册时约定参数的方式, 感觉跟注册实例的方式很像, 为了解答我的疑惑, 不得不亲自试验一遍.

    builder.RegisterInstance<Person>(new Person("liang", 22));
    //-------------------------------------------------
    var person = container.Resolve<Person>();
    person.Self();
    person.Age += 10;
    
    var personA = container.Resolve(typeof(Person), new NamedParameter("name", "elvin"), new NamedParameter("age", 18)) as Person;
    personA.Self();
    person.Age += 10;
    
    var personB = container.Resolve(typeof(Person), new NamedParameter("MyPerson", new Dog() { Name = "小花" })) as Person;
    personB.Self();

    从这里看到, 虽然都是在注册时, 给了构造函数的约定, 但是还是有天差地别的. 注册实例的方式有点类似于单例.

    三、自动装配

    通过程序集扫描的方式, 可以自动装配, 省去许多配置的工作和重复的工作

    builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly());
    builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()).AsImplementedInterfaces();
    //-------------------------------------------------
    var person = container.Resolve<IPerson>();
    person.Self();
    
    var personA = container.Resolve<Person>();
    personA.Self();
    
    var animal = container.Resolve<IAnimal>();
    animal.Say();

    这里为什么会调用一个参数的构造函数呢, 为此我修改了Cat类, 加入了两个构造函数, 一个无参, 一个string name参数, 发现调用的时候, Cat这里还是无参的构造函数. 

    然后我又修改了Person的一个参数的构造函数, 将参数改为string name, 运行之后发现调用的就是无参的构造函数了, 从这些现象来看, 影响到autofac选择构造函数的, 应该就是 IAnimal 这个了. 然后我又加了一个三参构造函数, Person(IAnimal myPerson, string name, int age), 发现还是调用的无参构造函数. 

    builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly());
    builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()).AsImplementedInterfaces();
    
    //-------------------------------------------------
    var person = container.Resolve<IPerson>();
    person.Self();

     我大致看了一下源码

    这个方法中, 程序会根据参数去查找是否有容器中的参数, 如果有的话, 会选择使用匹配上的构造函数, 这里有一个原则, 就是使用匹配个数最多的那个构造函数, 但是这个构造函数又要做到参数尽可能的少. 是不是有点晕, 给个例子就清晰了

    public Person(string name)
    {
        Console.WriteLine("一个参数name构造函数");
        this.Name = name;
    }
    public Person(IAnimal MyPerson)
    {
        Console.WriteLine("两个参数IAnimal, IGo构造函数");
        adopt = MyPerson;
    }
    
    
    public Person(IAnimal MyPerson, IGo go)
    {
        Console.WriteLine("两个参数IAnimal, IGo构造函数");
        adopt = MyPerson;
        this.go = go;
    }
    
    public Person(IAnimal myPerson, string name, int age)
    {
        Console.WriteLine("三个参数构造函数");
        this.Name = name;
        this.Age = age;
        adopt = myPerson;
    }
    
    public Person(IAnimal myPerson, IGo go, string name, int age)
    {
        Console.WriteLine("四个参数构造函数");
        this.Name = name;
        this.Age = age;
        adopt = myPerson;
        this.go = go;
    }

    ok, 自动匹配规则已经浮出水面了

  • 相关阅读:
    CodeForces 659F Polycarp and Hay
    CodeForces 713C Sonya and Problem Wihtout a Legend
    CodeForces 712D Memory and Scores
    CodeForces 689E Mike and Geometry Problem
    CodeForces 675D Tree Construction
    CodeForces 671A Recycling Bottles
    CodeForces 667C Reberland Linguistics
    CodeForces 672D Robin Hood
    CodeForces 675E Trains and Statistic
    CodeForces 676D Theseus and labyrinth
  • 原文地址:https://www.cnblogs.com/elvinle/p/6170294.html
Copyright © 2011-2022 走看看