通过通用接口/抽象类实现使 .NET Core DI 自动解析类 [英] Make .NET Core DI auto resolve class by generic interface / abstract class implementation

查看:30
本文介绍了通过通用接口/抽象类实现使 .NET Core DI 自动解析类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

比如我有如下界面:

公共接口 IMapper{}

我也有一个抽象类:

公共抽象类 Mapper: IMapper<TFrom, TTo>{受保护的映射器(){//一些通用的东西}公共抽象 TTo 映射(TFrom);}

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

public class UserMapper : Mapper{公共覆盖 Entity.User Map(Domain.User from){//做映射}}

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

例如,如果我在代码中的某处执行此操作:

class SomeClass{public SomeClass(IMapper<Domain.User, Entity.User> mapper) {}}

它以某种方式知道它应该解析类 UserMapper?

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

解决方案

当前设计的唯一方法是使用反射:

Assembly assembly = typeof(UserMapper).Assembly;foreach(在 assembly.GetTypes() 中的 var 类型.Where(t => t.IsClass && !t.IsAbstract)){foreach (var i in type.GetInterfaces()){if (i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IMapper<,>)){//注意:由于 Microsoft.DependencyInjection 的限制,我们不能//注册一个开放的泛型接口类型,而没有一个开放的泛型//实现类型.所以,我们转换为一个封闭的通用接口//要注册的类型.var interfaceType = typeof(IMapper<,>).MakeGenericType(i.GetGenericArguments());services.AddTransient(interfaceType, type);}}}

<块引用>

注意:您可以通过在 IServiceCollection 上创建一个扩展方法来简化它,并使用 AddTransientAddSingleton 等的各种重载

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

public class Mapper: IMapper<TFrom, TTo>{//...}

然后你可以像这样简单地注册:

services.AddTransient(typeof(IMapper<,>), typeof(Mapper<,>));

Is there a way in .NET Core to register a generic interface, and make it resolve a class that matches a certain implementation.

For example, I have the following interface:

public interface IMapper<TFrom, TTo>
{
}

I also have an abstract class:

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

    public abstract TTo Map(TFrom);
}

I can then create an implementation like so:

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

Is there a way, using the default .NET Core DI to register IMapper<,>, and let it auto resolve the class?

So if I for example would do this somewhere in code:

class SomeClass
{
    public SomeClass(IMapper<Domain.User, Entity.User> mapper) {}
}

That it somehow knows that it should resolve the class UserMapper<Domain.User, Entity.User>?

The reason is that it's a little verbose to manually register each and every mapper, specific to an implementation. So I'm hoping Microsoft.DependencyInjection is smart enough to automatically resolve its implementation somehow.

解决方案

The only way with your current design is to use 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);
        }
    }
}

NOTE: You could make it simpler by creating an extension method on IServiceCollection with the various overloads for AddTransient, AddSingleton, etc.

If you change the design use a non-abstract generic as your implementation type:

public class Mapper<TFrom, TTo> : IMapper<TFrom, TTo>
{
    //...
}

Then you can simply register like this:

services.AddTransient(typeof(IMapper<,>), typeof(Mapper<,>));

这篇关于通过通用接口/抽象类实现使 .NET Core DI 自动解析类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆