通过通用接口/抽象类实现使.NET Core DI自动解析类

Viv*_*ndi 1 c# dependency-injection inversion-of-control .net-core

.NET Core中是否有一种方法可以注册通用接口,并使其解析与某个实现相匹配的类.

例如,我有以下界面:

public interface IMapper<TFrom, TTo>
{
}
Run Code Online (Sandbox Code Playgroud)

我还有一个抽象类:

public abstract class Mapper<TFrom, TTo> : IMapper<TFrom, TTo>
{
    protected Mapper()
    {
        // some generic stuff
    }

    public abstract TTo Map(TFrom);
}
Run Code Online (Sandbox Code Playgroud)

然后我可以创建一个这样的实现:

public class UserMapper : Mapper<Domain.User, Entity.User>
{
    public override Entity.User Map(Domain.User from)
    {
        // do mapping
    }
}
Run Code Online (Sandbox Code Playgroud)

有没有办法,使用默认的.NET Core DI进行注册IMapper<,>,让它自动解析类?

所以,例如,如果我在代码中的某个地方执行此操作:

class SomeClass
{
    public SomeClass(IMapper<Domain.User, Entity.User> mapper) {}
}
Run Code Online (Sandbox Code Playgroud)

它以某种方式知道它应该解决这个类UserMapper<Domain.User, Entity.User>

原因是手动注册每个映射器有点冗长,特定于实现.所以我希望Microsoft.DependencyInjection能够以某种方式自动解决其实现.

Nig*_*888 6

您当前设计的唯一方法是使用Reflection:

Assembly assembly = typeof(UserMapper).Assembly;

foreach (var type in assembly.GetTypes()
    .Where(t => t.IsClass && !t.IsAbstract))
{
    foreach (var i in type.GetInterfaces())
    {
        if (i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IMapper<,>))
        {
            // NOTE: Due to a limitation of Microsoft.DependencyInjection we cannot 
            // register an open generic interface type without also having an open generic 
            // implementation type. So, we convert to a closed generic interface 
            // type to register.
            var interfaceType = typeof(IMapper<,>).MakeGenericType(i.GetGenericArguments());
            services.AddTransient(interfaceType, type);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:您可以把它简单的创建一个扩展方法IServiceCollection与不同的重载AddTransient,AddSingleton等等.

如果更改设计,请使用非抽象泛型作为实现类型:

public class Mapper<TFrom, TTo> : IMapper<TFrom, TTo>
{
    //...
}
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样注册:

services.AddTransient(typeof(IMapper<,>), typeof(Mapper<,>));
Run Code Online (Sandbox Code Playgroud)