【问题标题】:How to inject dependencies of generics in ASP.NET Core如何在 ASP.NET Core 中注入泛型的依赖项
【发布时间】:2016-09-04 18:37:24
【问题描述】:

我有以下存储库类:

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>    
{
    ...
}

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

我是这样实现的:

services.AddScoped(typeof(IRepository<>), typeof(Repository<>));

然后我得到以下错误:

无法实例化实现类型“Test.Domain.Repository1[T]' for service type 'Test.Domain.IRepository1[T]”。

【问题讨论】:

    标签: c# generics dependency-injection asp.net-core


    【解决方案1】:

    Repository&lt;T&gt; 是一个抽象类,因此您不能将其注册为实现,因为抽象类根本无法实例化。如果Repository&lt;T&gt; 不是抽象的,您的注册就可以正常工作。

    如果你不能使存储库类非抽象,你可以注册你的存储库类的具体实现:

    services.AddScoped(typeof(IRepository<Test>), typeof(TestRepository));
    

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

    【讨论】:

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

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

    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;
                    }
                }
            });
    }
    

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

    services.AddClassesAsImplementedInterface(Assembly.GetEntryAssembly(), typeof(IRepository<>));
    

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

    【讨论】:

      【解决方案3】:

      您只能将抽象类注册为服务,而不是像@dotnetom 所说的实现。

      请参阅下面的定义

       public abstract class BaseClass<T>
      {
      
          public BaseClass()
          {
          }
      }
      
      public class DerivedClass : BaseClass<Entity>
      {
          public DerivedClass() : base() { }
      }
      
      public class DerivedClass2<T> : BaseClass<T> where T: Entity
      {
         
      }
      
      public class Entity
      {
      
      }
      

      控制器:

      public class WeatherForecastController : ControllerBase
          {
              ......
      
              public WeatherForecastController(BaseClass<Entity> baseClass)
              {
                  
              }
               ...
      }
      

      如果你以这种方式注入它们:

       services.AddScoped(typeof(BaseClass<>), typeof(DerivedClass));
      

      在解决依赖关系时会出现此错误:

      开放通用服务类型“BaseClass`1[T]”需要注册开放通用实现类型。 (参数“描述符”)

      您应该注册泛型类型或使用定义的泛型参数注册服务和实现

      现在这应该也可以正常工作了

      services.AddScoped(typeof(BaseClass<>), typeof(DerivedClass2<>));
      

      或

      services.AddScoped(typeof(BaseClass<Entity>), typeof(DerivedClass2<Entity>));
      

      恕我直言,我更喜欢使用接口定义而不是抽象类。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-01-17
        • 1970-01-01
        • 2018-01-16
        • 2019-02-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多