依赖注入的源码是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;
    }
}
ServiceRegistry

相关文章:

  • 2022-12-23
  • 2021-11-30
  • 2021-10-23
  • 2021-11-12
  • 2021-08-09
  • 2021-11-20
猜你喜欢
  • 2022-01-20
  • 2021-09-13
  • 2021-07-28
  • 2021-12-03
  • 2022-01-27
  • 2021-09-17
  • 2021-06-19
相关资源
相似解决方案