.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中。
- 构造函数注入:如果对象A在构造函数中依赖于对象B,对象B在构造函数中依赖于对象C,如果要构造对象A,自动构造C,传入对象B的构造函数,构造出对象B,传入对象A,构造出对象A;
- 属性注入:如果对象A在属性中依赖于对象B,对象B在属性中依赖于对象C,如果要构造对象A,在构造出对象A之后,检测属性,如果属性有依赖,就自动的去创建依赖的对象,创建出来以后,赋值给对象A中共的属性; 如果在创建的过程中,还有依赖,就继续创建
- 方法注入:如果对象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>();
本文来自博客园,作者:一纸年华,转载请注明原文链接:https://www.cnblogs.com/nullcodeworld/p/18363242