天天看點

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();      
Autofac - 裝配

這種方式, 就是通過傳參來控制調用哪一個構造函數, 其内部是通過反射的方式去實作的.

如果使用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();      
Autofac - 裝配

有圖有真相哦.

二、額外的構造函數參數

添加構造函數, 有兩個地方可以添加, 一個是在注冊的時候添加, 另一個是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();      
Autofac - 裝配

這個時候, 我發現, 無參的寫法和有參的寫法, 都不會報錯, 而且, 在建立執行個體的時候, 都是調用的兩個參數的構造函數

如果這個時候, 我使用一個參數的方式去寫

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

這個時候, 會發現, 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();      
Autofac - 裝配

從這裡看到, 雖然都是在注冊時, 給了構造函數的約定, 但是還是有天差地别的. 注冊執行個體的方式有點類似于單例.

三、自動裝配

通過程式集掃描的方式, 可以自動裝配, 省去許多配置的工作和重複的工作

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();      
Autofac - 裝配

這裡為什麼會調用一個參數的構造函數呢, 為此我修改了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();      
Autofac - 裝配

 我大緻看了一下源碼

Autofac - 裝配

這個方法中, 程式會根據參數去查找是否有容器中的參數, 如果有的話, 會選擇使用比對上的構造函數, 這裡有一個原則, 就是使用比對個數最多的那個構造函數, 但是這個構造函數又要做到參數盡可能的少. 是不是有點暈, 給個例子就清晰了

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;
}      
Autofac - 裝配

ok, 自動比對規則已經浮出水面了