依赖注入的源码是Microsoft.Extensions.DependencyInjection命名空间下的,项目结构比较复杂,本文先从先从简单的实现开始,一起了解下依赖注入最基础的实现
最基础的依赖注入
依赖注入容器
public class Cat { /// <summary> /// 线程安全的集合去保存所有的类型 /// </summary> private ConcurrentDictionary<Type, Type> typeMapping = new ConcurrentDictionary<Type, Type>(); //注册到容器中 public void Register(Type from, Type to) { typeMapping[from] = to; } //这个是核心方法 public object GetService(Type serviceType) { #region 构造函数注入 Type type; if (!typeMapping.TryGetValue(serviceType, out type)) { type = serviceType; } if (type.IsInterface || type.IsAbstract) { return null; } //获取构造函数的基本信息 ConstructorInfo constructor = this.GetConstructor(type); if (null == constructor) { return null; } //这里递归的获取了所有需要的实例 object[] arguments = constructor.GetParameters().Select(p => GetService(p.ParameterType)).ToArray(); //根据获得的参数调用构造函数 得到所需对象service object service = constructor.Invoke(arguments); #endregion return service; } /// <summary> /// 获取对应类型的构造器 /// </summary> /// <param name="type"></param> /// <returns></returns> protected virtual ConstructorInfo GetConstructor(Type type) { ConstructorInfo[] constructors = type.GetConstructors(); //如果我们有标记了InjectionAttribute 那么就用标记了的构造器 return constructors.FirstOrDefault(c => c.GetCustomAttribute<InjectionAttribute>() != null) ?? constructors.FirstOrDefault(); } }
扩展方法
public static class CatExtensions { public static T GetService<T>(this Cat cat) { if (cat == null) { throw new ArgumentNullException("collection"); } return (T)cat.GetService(typeof(T)); } public static void Register<TService, TImplementation>(this Cat cat) { if (cat == null) { throw new ArgumentNullException("collection"); } cat.Register(typeof(TService), typeof(TImplementation)); } }
实际使用
public interface IFoo { } public interface IBar { } public class Bar : IBar { } public class Foo : IFoo { public IBar Bar { get; private set; } public Foo() { } [Injection] public Foo(IBar bar) { this.Bar = bar; } } main方法 Cat cat = new Cat(); cat.Register<IFoo, Foo>(); cat.Register<IBar, Bar>(); IFoo service = cat.GetService<IFoo>(); Foo foo = (Foo)service; Console.WriteLine("cat.GetService<IFoo>(): {0}", service); Console.WriteLine("cat.GetService<IFoo>().Bar: {0}", foo.Bar);
这里我们通过public class InjectionAttribute : Attribute { } 标记需要注入的构造函数,然后我们简单的容器就会根据特性去选择对应执行的构造方法。
带有实例生命周期管理的依赖注入
ServiceRegistry
使用ServiceRegistry类进行服务注册的基础单元,我们将针对同一个服务类型(ServiceType属性相同)的多个ServiceRegistry组成一个链表,作为相邻节点的两个ServiceRegistry对象通过Next属性关联起来。我们为ServiceRegistry定义了一个AsEnumerable方法是它返回由当前以及后续节点组成的ServiceRegistry集合。
public enum Lifetime { Singlelton, Self, Transient } public class ServiceRegistry { public Type ServiceType { get; } public Lifetime Lifetime { get; } /// <summary> /// core的依赖注入还有实例模式,这里只有工厂模式做展示 /// </summary> public Func<Cat, Type[], object> Factory { get; } /// <summary> /// 同一个服务类型(ServiceType属性相同)的多个ServiceRegistry组成一个链表 /// </summary> internal ServiceRegistry Next { get; set; } public ServiceRegistry(Type serviceType, Lifetime lifetime, Func<Cat, Type[], object> factory) { ServiceType = serviceType; Lifetime = lifetime; Factory = factory; } public IEnumerable<ServiceRegistry> AsEnumerable() { var list = new List<ServiceRegistry>(); for (var self = this; self != null; self = self.Next) { list.Add(self); } return list; } }