• 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, 自动匹配规则已经浮出水面了

  • 相关阅读:
    VBA的几个小Demo_2
    VBA的几个小Demo
    Django部署在阿里云服务器上
    python面试题及解析
    Django知识扩展
    Django文件下载2
    Django文件下载
    Django文件上传
    My_First_Web
    10个jQuery小技巧
  • 原文地址:https://www.cnblogs.com/elvinle/p/6170294.html
Copyright © 2020-2023  润新知