C#依赖注入相同Generic Type的多个实现

Posted

技术标签:

【中文标题】C#依赖注入相同Generic Type的多个实现【英文标题】:C# dependency injection multiple implementation of the same Generic Type 【发布时间】:2021-01-18 15:06:53 【问题描述】:

注意:这不是重复的!

我有以下示例

public interface IRepository<TEntity> where TEntity : IEntity

...



public class Repository<TEntity> : IRepository<TEntity> where TEntity : IEntity

...



public class Repository<SpecialClass> : IRepository<SpecialClass> 


...



public class SpecialClass: IEntity

...

现在我想为每个IRepository&lt;&gt; 使用Repository&lt;&gt; 类,IRepository&lt;SpecialClass&gt; 除外:

// every IRepository<> :
services.AddScoped(typeof(IRepository<>), typeof(RepositoryEFCore<>));

// but not for SpecialClass
services.AddScoped(typeof(IRepository<SpecialClass>), typeof(Repository<SpecialClass>));

问题是我如何为同一个接口注册两个(或多个)不同的类,而该接口已经为另一个类注册了?

【问题讨论】:

切换注册顺序,看看是否有效。先注册特例。我还假设这是使用默认的内置容器。 @Nkosi,我怀疑切换顺序会很重要。如果我错了,请纠正我。 我似乎没有明白你的问题。在我看来,您的代码似乎已经完成了您想要的操作。如果您使用的是默认 DI,那么订单就像@Nkosi 所说的那样重要。如果您先注册通用,然后注册特定,当您解析 IRepository&lt;SpecialClass&gt; 时,DI 会注入最后添加的服务,在您的情况下为 Repository&lt;SpecialClass&gt; 【参考方案1】:
services.AddScoped(typeof(IRepository<>), typeof(RepositoryEFCore<>));

此行将在 DI 容器中添加所有 IRepository 处理程序。要从 DI 注册中排除某些特殊类,有一种使用反射的方法,

 Type[] handlers = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.IsClass && t.Name != "SpecialClass" &&  t.GetInterfaces().
        Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IRepository<>))).ToArray();

        foreach (Type concreteHandler in handlers)
        
            Type? handlerInterface = concreteHandler.GetInterfaces().First(i => i.GetGenericTypeDefinition() == typeof(IRepository<>));
            services.AddScoped(handlerInterface, concreteHandler);
        

这里,handlers 数组将保存 IRepository 的所有具体实现,不包括 Specialclass,使用 foreach 您可以在 DI 中添加所有具有具体实现的对象。

【讨论】:

以上是关于C#依赖注入相同Generic Type的多个实现的主要内容,如果未能解决你的问题,请参考以下文章

c#依赖注入和控制反转的书籍

C#中的依赖注入那些事儿

C#反射与特性:设计一个仿ASP.NETCore依赖注入Web

[巩固C#] 依赖注入是什么?

.NET依赖注入之一个接口多个实现

ASP.NET Core依赖注入高级玩法——如何注入多个服务实现类