在开发过程中手动注入接口和实现很麻烦而且代码很冗余

所以需要整一个自动注入的方法解放双手

需要定义一个注入类型的枚举

/// <summary>
/// 注入类型
/// </summary>
public enum InjectType
{
    //作用域
    Scope,

    //单例
    Single,

    //瞬时
    Transient
}

定义一个Attribute

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class AutoInjectAttribute : Attribute
{
    public AutoInjectAttribute(Type interfaceType, InjectType injectType)
    {
        Type = interfaceType;
        InjectType = injectType;
    }

    public Type Type { get; set; }

    /// <summary>
    /// 注入类型
    /// </summary>
    public InjectType InjectType { get; set; }
}

自动依赖注入的方法

/// <summary>
/// 自动依赖注入
/// </summary>
public static class AutoInject
{
    /// <summary>
    /// 自动注入所有的程序集有InjectAttribute标签
    /// </summary>
    /// <param name="serviceCollection"></param>
    /// <returns></returns>
    public static IServiceCollection AddAutoDI(this IServiceCollection serviceCollection)
    {
        var path = AppDomain.CurrentDomain.BaseDirectory;
        var assemblies = Directory.GetFiles(path, "*.dll").Select(Assembly.LoadFrom).ToList();
        foreach (var assembly in assemblies)
        {
            var types = assembly.GetTypes().Where(a => a.GetCustomAttribute<AutoInjectAttribute>() != null)
                .ToList();
            if (types.Count <= 0) continue;
            foreach (var type in types)
            {
                var attr = type.GetCustomAttribute<AutoInjectAttribute>();
                if (attr?.Type == null) continue;
                switch (attr.InjectType)
                {
                    case InjectType.Scope:
                        serviceCollection.AddScoped(attr.Type, type);
                        break;
                    case InjectType.Single:
                        serviceCollection.AddSingleton(attr.Type, type);
                        break;
                    case InjectType.Transient:
                        serviceCollection.AddTransient(attr.Type, type);
                        break;
                    default:
                        throw new ArgumentOutOfRangeException();
                }
            }
        }

        return serviceCollection;
    }
}

实现层和接口层

/// <summary>
/// 实现层调用特性
/// </summary>
[AutoInject(typeof(IHomeDataService), InjectType.Scope)]
public class HomeDataService: IHomeDataService
{
    public string GetUser()
    {
        return "张三";
    }
}

/// <summary>
/// 接口层不需要做任何处理
/// </summary>
public interface IHomeDataService
{
    string GetUser();
}

Program注册到服务

var builder = WebApplication.CreateBuilder(args);
// 自动注入
builder.Services.AddAutoDI();

即可完成自动注入

第二种方法扩展性更高,先定义三个接口对应三个生命周期

/// <summary>
/// 单例
/// </summary>
public interface ISingleton
{
}
/// <summary>
/// 瞬时
/// </summary>
public interface ITransient
{
}
/// <summary>
/// 作用域
/// </summary>
public interface IScoped
{
}

自动注入的方法

public static IServiceCollection AddDataService(this IServiceCollection services)
{
    var singletonType = typeof(ISingleton); // 单例
    var transientType = typeof(ITransient); // 瞬时
    var scopedType = typeof(IScoped); // 作用域
    // 获取实现了三个生命周期接口的程序集
    var allTypes = AppDomain.CurrentDomain.GetAssemblies()
        .SelectMany(a => a.GetTypes().Where(t =>
        t.GetInterfaces().Contains(transientType) ||
        t.GetInterfaces().Contains(singletonType)||
        t.GetInterfaces().Contains(scopedType)));
    // class的程序集
    var implementTypes = allTypes.Where(x => x.IsClass).ToArray();
    // 接口的程序集
    var interfaceTypes = allTypes.Where(x => x.IsInterface).ToArray();
    foreach (var implementType in implementTypes)
    {
        var interfaceType = interfaceTypes.FirstOrDefault(x => x.IsAssignableFrom(implementType));
        // class有接口,用接口注入
        if (interfaceType != null)
        {
            // 判断用什么方式注入
            if (interfaceType.GetInterfaces().Contains(singletonType))
            {
                // 单例
                services.AddSingleton(interfaceType, implementType);
            }
            else if (interfaceType.GetInterfaces().Contains(transientType))
            {
                // 瞬时
                services.AddTransient(interfaceType, implementType);
            }
            else if(interfaceType.GetInterfaces().Contains(scopedType))
            {
                // 作用域
                services.AddScoped(interfaceType, implementType);
            }
        }
        else // class没有接口,直接注入class
        {
            // 判断用什么方式注入
            if (implementType.GetInterfaces().Contains(singletonType))
            {
                // 单例
                services.AddSingleton(implementType);
            }
            else if(implementType.GetInterfaces().Contains(transientType))
            {
                // 瞬时
                services.AddTransient(implementType);
            }
            else if (implementType.GetInterfaces().Contains(scopedType))
            {
                // 作用域
                services.AddScoped(implementType);
            }
        }
    }
    return services;
}

Program注册服务

// 自动注入
builder.Services.AddDataService();

使用方法:在需要使用的接口继承对应生命周期的接口即可

/// <summary>
/// 实现层不做处理
/// </summary>
public class HomeDataService: IHomeDataService
{
    public string GetUser()
    {
        return "张三";
    }
}

/// <summary>
/// 接口层继承生命周期接口
/// </summary>
public interface IHomeDataService: ISingleton
{
    string GetUser();
}

被这风吹散的人说Ta爱的不深,被这雨淋湿的人说Ta不会冷