带参数的开放泛型的依赖注入

Dependency Injection of open generics with arguments

文章讨论了如何在 .Net Core 中注册通用接口。但是,我有一个具有多个参数的通用接口,并且无法弄清楚注册和构造函数注入。

我的接口有 4 个参数

public class TestImplementation 
{
    // Try to inject IRepository here ??????
    public TestImplementation(.......)
    {
        ...
    }
}

public class Repository : IRepository<Test1, Test2, Test3, Test4> 
{
    ...
}

public interface IRepository<T, U, V, W> where T : ITemplate1 where U : ITemplate2,...  
{
    ...
}

如果我尝试将接口注入任何 class,它会给我错误,因为即使在代码的其他部分使用以下代码也无法解析接口

services.GetService(typeof(IRepository<,,,>))

我尝试使用构造函数注入,但它使编译器不高兴(在尝试激活 xxxx 时无法解析类型'....Interface....' 的服务),因为我想保持接口打开。但是我在代码中解析了接口

正确的方法是不注入 Repository 服务。它应该只用作具有功能的模板。然后,您创建一个额外的 class 继承自 Repository class 和一个继承自 IRepository 的接口。这样您就可以分配通用值的值,然后以一种整洁且受控的方式注入它。

乍一看,这个模式可能看起来有点额外的工作,但它允许为每个 table 存储库自定义功能,清楚地表明您正在使用哪个 table 并允许轻松替换不同的数据库。请参阅下面的示例:

正如您所拥有的那样,创建您的 RepositoryIRepository 界面:

public abstract class Repository<T, U, V, W> : IRepository<T, U, V, W> 
{
    ...
}

public interface IRepository<T, U, V, W> where T : ITemplate1 where U : ITemplate2,...  
{
    ...
}

现在为您的特定 table 创建一个界面。首先是界面:

public interface ISomeTableRepository : IRepository<input_1, input_2, ...> {}

现在创建 class 存储库:

public class SomeTableRepository : Repository<input_1, input_2,...> , ISomeTableRepository {}

现在您将这些注册到 Startup.cs 文件中没有输入的新存储库。

services.AddScoped<ISomeTableRepository, SomeTableRepository> ();

现在无需添加参数即可轻松注入:

public class TestImplementation 
{
    readonly ISomeTableRepository _someTable;

    
    public TestImplementation(ISomeTableRepository someTable)
    {
        _someTable = someTable;
    }
}

将未绑定泛型类型中的任何成员放入派生类型实现的基类型中。

对于未知类型的值,您可以使用 objectdynamic

看这个例子:

public interface IRepository
{
    object TV { get; set; }
    object UV { get; set; }
    object VV { get; set; }
    object WV { get; set; }
}

public interface IRepository<T, U, V, W>: IRepository
{
    object IRepository.TV { get => TV; set => TV = (T)value; }
    object IRepository.UV { get => UV; set => UV = (U)value; }
    object IRepository.VV { get => VV; set => VV = (V)value; }
    object IRepository.WV { get => WV; set => WV = (W)value; }
    new T TV { get; set; }
    new U UV { get; set; }
    new V VV { get; set; }
    new W WV { get; set; }
}

那么,你可以这样做:

services.GetService(typeof(IRepository))

没有任何问题。

https://dotnetfiddle.net/kwoOOe