如何在ASP.NET Core中注入泛型的依赖关系

Pal*_*lmi 8 c# generics dependency-injection asp.net-core

我有以下存储库类:

public class TestRepository : Repository<Test>
{
    private TestContext _context;

    public TestRepository(TestContext context) : base(context)
    {
        _context = context;
    }
}

public abstract class Repository<T> : IRepository<T> where T : Entity
{
    private TestContext _context;

    public Repository(TestContext context)
    {
        _context = context;
    }
    ...
}

public interface IRepository<T>    
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

如何在我的ASP.NET Core中实现依赖注入Startup.cs

我这样实现了:

services.AddScoped(typeof(IRepository<>), typeof(Repository<>));
Run Code Online (Sandbox Code Playgroud)

但后来我得到以下错误:

无法实例化实现类型'Test.Domain.Repository 1[T]' for service type 'Test.Domain.IRepository1 [T]'.

dot*_*tom 17

Repository<T>是一个抽象类,因此您无法将其注册为实现,因为抽象类根本无法实例化.如果Repository<T>不是抽象的,您的注册将正常工作.

如果您不能使存储库类非抽象,则可以注册存储库类的特定实现:

services.AddScoped(typeof(IRepository<Test>), typeof(TestRepository));
Run Code Online (Sandbox Code Playgroud)

这将正确地将依赖项注入您的控制器.

  • 你也可以使用通用的`AddScoped`方法,它不那么冗长:`services.AddScoped <IRepository <Test>,TestRepository>()` (2认同)
  • 注意:如果你注册了一个泛型实例,比如 services.AddScoped(typeof(IRepository&lt;&gt;), typeof(GenericRepository&lt;&gt;)),你也不能提供一个在特定情况下覆盖通用实例的特定实例。这会生成一个错误“开放通用服务类型‘IRepository`1[T]’需要注册一个开放的通用实现类型”,这是不正确的,因为您如何注册了一个开放的通用实现。 (2认同)

小智 7

我知道这已经很晚了,但我在这里发布了我的解决方案,以便其他人可以参考和使用它。我编写了一些扩展来注册泛型接口的所有派生类型。

public static List<TypeInfo> GetTypesAssignableTo(this Assembly assembly, Type compareType)
{
        var typeInfoList = assembly.DefinedTypes.Where(x => x.IsClass 
                            && !x.IsAbstract 
                            && x != compareType
                            && x.GetInterfaces()
                                    .Any(i => i.IsGenericType
                                            && i.GetGenericTypeDefinition() == compareType))?.ToList();

        return typeInfoList;
 }

public static void AddClassesAsImplementedInterface(
        this IServiceCollection services, 
        Assembly assembly, 
        Type compareType,
        ServiceLifetime lifetime = ServiceLifetime.Scoped)
 {
        assembly.GetTypesAssignableTo(compareType).ForEach((type) =>
        {
            foreach (var implementedInterface in type.ImplementedInterfaces)
            {
                switch (lifetime)
                {
                    case ServiceLifetime.Scoped:
                        services.AddScoped(implementedInterface, type);
                        break;
                    case ServiceLifetime.Singleton:
                        services.AddSingleton(implementedInterface, type);
                        break;
                    case ServiceLifetime.Transient:
                        services.AddTransient(implementedInterface, type);
                        break;
                }
            }
        });
}
Run Code Online (Sandbox Code Playgroud)

在启动类中,您只需注册您的通用接口,如下所示。

services.AddClassesAsImplementedInterface(Assembly.GetEntryAssembly(), typeof(IRepository<>));
Run Code Online (Sandbox Code Playgroud)

您可以在此Github存储库中找到完整的扩展代码。