.Net 内置 IOC 容器和依赖注入

1 依赖倒置

依赖倒置的核心价值:
如果没有依赖倒置,全部都是依赖细节,如果分层架构是 A层---B层--C层---D层---E层---F层,下层的修改,可能会导致上层随之改变,F层如果改变,E层要改,D层要改,C层要改......影响很大,成水波式向上影响,架构就的极度不稳定。
如果都是依赖于抽象的,抽象即接口或抽象类。 抽象是相对稳定的,修改下层不会影响上层。因为上层不是依赖于具体的,这让我们的代码更加稳定。
IOC 控制对象的创建,不就是完全控制了对象的创建吗?所以,IOC的本质是工厂。
既然 IOC 是工厂,那么工厂生产产品就是创建对象。

2 简单工厂创建对象会不会有什么问题呢?

工厂创建对象,如果对象没有无参数构造函数,必须得按照构造函数参数的要求,准备好构造函数。那就会出现问题:如果对象存在层层依赖,有多少层依赖,就得准备多少个方法。
要解决这个问题,我们就有了这样的一个目标:如果有依赖的,能够做到,在创建对象的时候,能够自动把对象依赖的对象给创建出来,然后传递进去,这样就很好。
.Net Core的内置IOC容器可以帮助我们解决掉这个问题。

3 内置IOC容器

需要引入Microsoft.Extensions.DependencyInjection包。
Zlt.IOC.Interfaces 命名空间下创建接口:

public interface IHeadphone
{
}
public interface IMicrophone
{
}   
public interface IPower
{
}
public interface IPhone
{
    void Call();
    void Init123456678890(IPower iPower);
    IMicrophone Microphone { get; set; }
    IHeadphone Headphone { get; set; }
    IPower Power { get; set; }
}

Zhaoxi.IOC.Services 实现接口:

    public class Headphone : IHeadphone
    { 
        public Headphone()
        {
            Console.WriteLine($"{this.GetType().Name}被构造。。");
        } 
    }
    public class Headphone : IHeadphone
    {
        public Headphone()
        {
            Console.WriteLine($"{GetType().Name}被构造。。");
        }
    }
    public class Microphone : IMicrophone
    {
        public IHeadphone _IHeadphone { get; set; }

        public IHeadphone _IHeadphoneField;

        public void SetHeadphone(IHeadphone headphone)
        {
            _IHeadphoneField = headphone;
        }

        /// <summary>
        /// 没有无参数构造函数
        /// </summary>
        /// <param name="headphone"></param>
        [SelectCtor]
        public Microphone(IHeadphone headphone)
        {
            Console.WriteLine($"{GetType().Name}被构造。。");
        }

        public Microphone(IHeadphone headphone, IHeadphone headphone1)
        {
            Console.WriteLine($"{GetType().Name}被构造。。");
        }
    }
    public class Power : IPower
    {
        public Power(IMicrophone microphone)
        {
            Console.WriteLine($"{GetType().Name}被构造。。");
        }
    }
    public class AndroidPhone : IPhone
    {
        public IMicrophone Microphone { get; set; }
        public IHeadphone Headphone { get; set; }
        public IPower Power { get; set; }

        public AndroidPhone(IPower Power)
        {
            Power = Power;
            Console.WriteLine("{0}构造函数", GetType().Name);
        }

        public void Call()
        {
            Console.WriteLine("{0}打电话", GetType().Name); ;
        }

        public void Init123456678890(IPower iPower)
        {
            Power = iPower;
        }
    }

调用:

//1.IOC容器的实例
ServiceCollection services = new();
//2.注册抽象和具体之间的关系
services.AddTransient<IHeadphone, Headphone>();
services.AddTransient<IMicrophone, Microphone>();
services.AddTransient<IPower, Power>();
services.AddTransient<IPhone, AndroidPhone>();
//3.Buidl下得到一个Provider
ServiceProvider serviceProvider = services.BuildServiceProvider();
//4.创建对象
IHeadphone headphone = serviceProvider.GetService<IHeadphone>();
IMicrophone microphone = serviceProvider.GetService<IMicrophone>();
IPower power = serviceProvider.GetService<IPower>();
IPhone iphone = serviceProvider.GetService<IPhone>();

这就是框架的依赖注入,如果对象A依赖于对象B,对象B依赖于对象C,在创建对象A时,自动先创建对象C,满足对象B的依赖,再创建对象B,满足A的依赖,最后创建出对象A。

4 依赖注入DI

内置容器中,仅支持构造函数注入这一种。依赖注入有3中。

  1. 构造函数注入:如果对象A在构造函数中依赖于对象B,对象B在构造函数中依赖于对象C,如果要构造对象A,自动构造C,传入对象B的构造函数,构造出对象B,传入对象A,构造出对象A;
  2. 属性注入:如果对象A在属性中依赖于对象B,对象B在属性中依赖于对象C,如果要构造对象A,在构造出对象A之后,检测属性,如果属性有依赖,就自动的去创建依赖的对象,创建出来以后,赋值给对象A中共的属性; 如果在创建的过程中,还有依赖,就继续创建
  3. 方法注入:如果对象A在某个方法中依赖于对象B,对象B在某个方法中依赖于对象C,如果要构造对象A,在构造出对象A之后,检测某个方法,如果某个方法的参数有依赖,就自动的去创建某个方法参数依赖的对象,创建出来以后,去执行这个方法,把构造出来的对象传递给这方法的参数; 如果在创建的过程中,还有方法依赖,就继续创建。

5 这个 IOC 和依赖注入 DI 之间,是什么关系?

IOC 是架构设计的一种方案,一种目标;
DI 是实现 IOC 容器的的时候,一种解决依赖问题的技术手段;

6 底层究竟如何实现?

下面就是关于IOC底层的构造函数注入的核心逻辑。
Zlt.IOC.Common 提供公共方法:

public interface IMyServiceCollection
{
    /// <summary>
    /// 注册具体和抽象之间的关系
    /// </summary>
    /// <typeparam name="T">抽象</typeparam>
    /// <typeparam name="S">具体</typeparam>
    public void Register<T, S>() where S : T;
    /// <summary>
    /// 获取对象的实例
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public T GetService<T>();
}
public class MyServiceCollection : IMyServiceCollection
{
    private static Dictionary<string, Type> MapDic = new Dictionary<string, Type>();
    /// <summary>
    ///  保存  注册具体和抽象之间的关系
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="S"></typeparam>
    public void Register<T, S>() where S : T
    {
        MapDic.Add(typeof(T).FullName, typeof(S));
    }
    /// <summary>
    ///  获取对象的实例
    /// </summary>
    /// <typeparam name="T">参数:必然是抽象</typeparam>
    /// <returns></returns>
    public T GetService<T>()
    {
        string abstractFullName = typeof(T).FullName;
        Type type = MapDic[abstractFullName];
        return (T)CreateInstance(type);
    }
    /// <summary>
    /// 创建对象 有依赖的递归创建
    /// </summary>
    /// <param name="type"></param>
    /// <returns></returns>
    public object CreateInstance(Type type)
    {
        ConstructorInfo? ctor = type.GetConstructors()
            .Where(a => a.IsDefined(typeof(SelectCtorAttribute)))
            .FirstOrDefault();
        if (ctor == null)
        {
            ctor = type.GetConstructors()
                .OrderByDescending(c => c.GetParameters().Length)
                .First();
        }
        List<object> parametList = new();
        foreach (var ctorParameter in ctor.GetParameters())
        {
            Type tageType = MapDic[ctorParameter.ParameterType.FullName];
            object oPrarmeter = CreateInstance(tageType);
            parametList.Add(oPrarmeter);
        }
        return Activator.CreateInstance(type, parametList.ToArray());
    }
}
[AttributeUsage(AttributeTargets.Constructor)]
public class SelectCtorAttribute : Attribute
{
}

调用:

IMyServiceCollection myServices = new MyServiceCollection();
myServices.Register<IHeadphone, Headphone>();
myServices.Register<IMicrophone, Microphone>();
myServices.Register<IPower, Power>();
myServices.Register<IPhone, AndroidPhone>();

IHeadphone headphone1 = myServices.GetService<IHeadphone>();
IMicrophone microphone1 = myServices.GetService<IMicrophone>();
IPower power1 = myServices.GetService<IPower>();
IPhone iphone1 = myServices.GetService<IPhone>();
posted @ 2024-08-16 17:04  一纸年华  阅读(25)  评论(0编辑  收藏  举报