这篇文章讲的是如何在.Net Core中注册Generic接口。然而,我有一个具有多个参数的通用接口,并且在弄清楚注册和构造函数注入时遇到了困难。
我的接口有 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,...
{
...
}
如果我尝试将接口注入任何类,它会给我错误,因为即使在代码的其他部分使用以下代码,接口也无法解析
services.GetService(typeof(IRepository<,,,>))
我尝试使用构造函数注入,但它使编译器不高兴(尝试激活 xxxx 时无法解析类型“....Interface....”的服务),因为我想保持接口打开。不过我在代码中解析了接口
正确的方法是不注入
Repository
服务。它应该仅用作具有功能的模板。然后,您创建一个继承自 Repository
类的附加类和一个继承自 IRepository
的接口。这样您就可以分配通用值的值,然后以整齐且受控的方式注入它。
乍一看,这种模式可能看起来有点额外的工作,但它允许为每个表存储库提供自定义功能,清楚地表明您正在使用哪个表,并允许轻松替换不同的数据库。请参阅下面的示例:
因此,创建您的
Repository
和 IRepository
界面:
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,...
{
...
}
现在为您的特定表创建一个界面。首先是界面:
public interface ISomeTableRepository : IRepository<input_1, input_2, ...> {}
现在创建类存储库:
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;
}
}
这个答案似乎得到了相当多的关注,这是我不久前写的。下面是另一种进行 DPI 的方法。如果您需要可靠性和性能,我仍然推荐上面的方法,但是对于快速方法,您可以使用
unbound
依赖注入。
因此,创建您的
Repository
和 IRepository
界面:
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,...
{
...
}
现在在启动或程序文件中将接口注册为未绑定:
services.AddTransient(typeof(IRepository<,,,>), typeof(Repository<,,,>)>
请注意,输入/变量的数量应与
<...>
之间的空格数量相关,因此,如果有 1 个输入,则为 <>
。如果有两个:<,>
,如果有三个<,,>
,依此类推。
无论您需要将未绑定泛型类型中的哪些成员放入派生类型实现的基类型中。
您可以使用
object
或 dynamic
来表示未知类型的值。
看这个例子:
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))
没有任何问题。