.NET

.NET Core 依赖注入改造(4)- ActivatorUt

2018-09-05  本文已影响41人  冰麟轻武

.NET Core 依赖注入改造(1)- 命名服务
.NET Core 依赖注入改造(2)- 委托转换
.NET Core 依赖注入改造(3)- ILogger
.NET Core 依赖注入改造(4)- ActivatorUtilities
.NET Core 依赖注入改造(5)- Context

.NET Core 依赖注入改造(附1)- Autowrite

一、

ActivatorUtilities

ActivatorUtilities 看注释就知道这是一个用于创建对象的帮助类

使用起来也很简单

CreateInstance

但是缺少了类似Java中的Autowrite功能

Autowrite

今天就改造这个

二、

先假想一个完成后的样子

static void Main(string[] args)
{
    var provider = new ServiceCollection()
                            .AddLogging()
                            .BuildServiceProvider();

    var a = new MyClass();
    provider.Autowrite(a);
}
class MyClass
{
    [Autowrite]
    private ILogger<MyClass> Logger { get; }
}

从上面这个代码中可以看出,需要先定义个AutowriteAttribute
然后实现一个扩展方法Autowrite(this IServiceProvider serviceProvider, object instance)

三、

AutowriteAttribute

[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
public sealed class AutowriteAttribute : Attribute, IServiceProviderFactory<IServiceProvider>
{
    public IServiceProvider CreateBuilder(IServiceCollection services) => throw new NotImplementedException();
    public IServiceProvider CreateServiceProvider(IServiceProvider containerBuilder) => containerBuilder;
}

这里实现了接口 IServiceProviderFactory<IServiceProvider>是为了更好的扩展性
看完扩展方法后就会明白

public static IServiceProvider Autowrite(this IServiceProvider serviceProvider, object instance)
{
    if (serviceProvider == null || instance == null)
    {
        return serviceProvider;
    }

    var flags = BindingFlags.Public | BindingFlags.NonPublic;
    var type = instance as Type ?? instance.GetType();
    if (instance is Type)
    {
        instance = null;
        flags |= BindingFlags.Static;
    }
    else
    {
        flags |= BindingFlags.Instance;
    }

    // 字段
    foreach (var field in type.GetFields(flags))
    {
        var attr = field.GetCustomAttributes().OfType<IServiceProviderFactory<IServiceProvider>>().LastOrDefault();
        var value = attr?.CreateServiceProvider(serviceProvider).GetServiceOrCreateInstance(field.FieldType);
        if (value != null)
        {
            field.SetValue(instance, value);
        }
    }

    foreach (var property in type.GetProperties(flags))
    {
        var attr = property.GetCustomAttributes().OfType<IServiceProviderFactory<IServiceProvider>>().LastOrDefault();
        var value = attr?.CreateServiceProvider(serviceProvider).GetServiceOrCreateInstance(property.PropertyType);
        if (value != null)
        {              
            var setter = property.GetSetMethod(true);
            if (setter != null)
            {   // 一般属性
                setter.Invoke(instance, new[] { value });
            }
            else if (type.GetField($"<{property.Name}>k__BackingField", flags) is FieldInfo field)
            {   // 只读属性
                field.SetValue(instance, value);
            }
        }
    }

    return serviceProvider;
}

仔细看这一行

GetCustomAttributes().OfType<IServiceProviderFactory<IServiceProvider>>().LastOrDefault()

可以看出在这里获取特性Attribute时,没有指定AutowriteAttribute类型,而是获取所有特性后筛选出实现 IServiceProviderFactory<IServiceProvider>接口的特性,进行下一步操作,所以这里方便随时扩展功能,重新实现一个特性代替AutowriteAttribute,进行部分行为干涉。

顺便多做了一个 GetServiceOrCreateInstance 扩展方法,等于
ActivatorUtilities.GetServiceOrCreateInstance+Autowrite

public static object GetServiceOrCreateInstance(this IServiceProvider serviceProvider, Type type)
{
    if (serviceProvider == null)
    {
        return Activator.CreateInstance(type);
    }

    var obj = ActivatorUtilities.GetServiceOrCreateInstance(serviceProvider, type);
    if (obj != null)
    {
        serviceProvider.Autowrite(obj);
    }
    return obj;
}

用于方便获取服务值时进行递归操作

var value = attr?.CreateServiceProvider(serviceProvider).GetServiceOrCreateInstance(property.PropertyType);
if (value != null)
{
    field.SetValue(instance, value);
}

四、

最终效果
ps: 也可以通过Type实例来注入静态属性或字段
static void Main(string[] args)
{
    var provider = new ServiceCollection()
                            .AddLogging()
                            .BuildServiceProvider();
    provider.Autowrite(typeof(MyClass));
}

class MyClass
{
    [Autowrite]
    public static ILogger<MyClass> Logger { get; }

    [Autowrite]
    private readonly static ILogger<MyClass> _logger;
}

五、

最后把ActivatorUtilities中的所有静态方法都扩展一遍

public static object GetServiceOrCreateInstance(this IServiceProvider serviceProvider, Type type)
{
    if (serviceProvider == null)
    {
        return Activator.CreateInstance(type);
    }

    var obj = ActivatorUtilities.GetServiceOrCreateInstance(serviceProvider, type);
    if (obj != null)
    {
        serviceProvider.Autowrite(obj);
    }
    return obj;
}

public static ObjectFactory CreateFactory(this IServiceProvider serviceProvider, Type instanceType, Type[] argumentTypes)
{
    var factory = ActivatorUtilities.CreateFactory(instanceType, argumentTypes);
    if (factory == null)
    {
        return factory;
    }
    return (provider, args) =>
    {
        var obj = factory(provider, args);
        if (obj != null)
        {
            provider?.Autowrite(obj);
        }
        return obj;
    };
}

public static object CreateInstance(this IServiceProvider provider, Type instanceType, params object[] parameters)
{
    var obj = ActivatorUtilities.CreateInstance(provider, instanceType, parameters);
    if (obj != null)
    {
        provider.Autowrite(obj);
    }
    return obj;
}

public static T CreateInstance<T>(this IServiceProvider provider, params object[] parameters) =>
    (T)CreateInstance(provider, typeof(T), parameters);

public static T GetServiceOrCreateInstance<T>(this IServiceProvider provider) =>
    (T)GetServiceOrCreateInstance(provider, typeof(T));

六、

github:https://github.com/blqw/blqw.DI/tree/master/src/blqw.DI.ExtensionMethods
nuget:https://www.nuget.org/packages/blqw.DI.ExtensionMethods

上一篇下一篇

猜你喜欢

热点阅读