c# - 通用类的自动注册
问题描述
我正在尝试使用 Simple Injector 注入一个泛型类。但是,它失败了
SimpleInjector.ActivationException:没有注册类型...找不到
这是重现它的代码:
using System;
namespace ErrorReproduction
{
public class GenericClass<T>
{
public T Value { get; set; }
}
public interface IGenericInterface<T>
{
void DoSomething(T value);
}
public class NonGenericService : IGenericInterface<string>
{
public void DoSomething(string value) =>
Console.WriteLine($"NonGeneric DoSomething (string): {value}");
}
public class GenericService<T> : IGenericInterface<GenericClass<T>>
{
public virtual void DoSomething(GenericClass<T> v) =>
Console.WriteLine(
$"Generic DoSomething {v.Value.GetType().Name}: {v.Value}");
}
/*
public class StringService : GenericService<string>
{
}
*/
public static class Test
{
public static void Main(string[] args)
{
var container = new SimpleInjector.Container();
container.RegisterSingleton(
typeof(IGenericInterface<>),
typeof(IGenericInterface<>).Assembly);
// works
container.GetInstance<IGenericInterface<string>>()
.DoSomething("non-generic-test");
// breaks without StringService (No registration for type
// IGenericInterface<GenericClass<string>>)
container.GetInstance<IGenericInterface<GenericClass<string>>>()
.DoSomething(
new GenericClass<string> {Value = "di-generic-test"});
}
}
}
如果我在上面的 StringService 中添加注释,它就可以工作。但是,如果没有它,我会收到以下异常:
未处理的异常。SimpleInjector.ActivationException:找不到类型 IGenericInterface<GenericClass<string>> 的注册。在 ErrorReproduction/Test.cs:line 45 中的 ErrorReproduction.Test.Main(String[] args)
如果我创建了一个本身不再是通用的特定实现,那么 DI 就可以工作。但是,即使没有具体的GenericService<T>
,不抽象的,也足够了,应该是可注入的。
我不想为GenericService<T>
我们将拥有的每种情况创建一个特定的类。它们就像上面一样是空的StringService
,完全依赖于通用服务的实现。
有没有办法让 DI 为这样的案例工作?
编辑:原来我的用例并不完全是我上面描述的。但是,提供的评论和答案使我走上了正确的道路。最后,这对我有用:
container.RegisterSingleton(typeof(IMapper<,>), typeof(IMapper<,>).Assembly);
container.RegisterConditional(typeof(IMapper<,>),
typeof(SimpleTimedValueProxyMapper<>),
Lifestyle.Singleton,
ctx => !ctx.Handled);
container.RegisterConditional(typeof(IMapper<,>),
typeof(TimedValueProxyMapper<,>),
Lifestyle.Singleton,
ctx => !ctx.Handled);
鉴于第一个示例中的类,可能会解决此问题(尚未测试):
container.RegisterSingleton(typeof(IGenericInterface<>), typeof(IGenericInterface<>).Assembly);
container.RegisterConditional(typeof(IGenericInterface<>),
typeof(GenericService<>),
Lifestyle.Singleton,
ctx => !ctx.Handled);
解决方案
XML 文档的RegisterXXX(Type, Assembly[])
状态如下(强调我的):
在给定的程序集中注册所有具体的、非泛型的、公共的和内部的类型
换句话说,默认情况下,只注册非泛型类型;您GenericService<T>
在此自动注册过程中被跳过。
这是设计使然,这样做是因为泛型类型通常需要特殊处理。这是因为它们很容易重叠,并且它们的注册顺序可能很重要。
因此,要解决此问题,您可以执行以下操作:
container.RegisterSingleton(
typeof(IGenericInterface<>),
typeof(IGenericInterface<>).Assembly);
container.RegisterSingleton(
typeof(IGenericInterface<>), typeof(GenericService<>));
当有许多泛型类型并且它们彼此不重叠时,您可以指示 Simple Injector 在注册中也包括泛型类型定义。这可以按如下方式完成:
container.Register(
typeof(IGenericInterface<>),
container.GetTypesToRegister(
typeof(IGenericInterface<>),
new[] { typeof(IGenericInterface<>).Assembly },
new TypesToRegisterOptions { IncludeGenericTypeDefinitions = true }));
推荐阅读
- python - TF Object Detection API:将指标保存到磁盘
- bash - 如何在 /bin/dash 中模拟“${@:2}”
- laravel - 在laravel中查询具有多个条件的数据库的有效方法
- random-forest - 在带有预处理的 GridSearchCV 管道中使用 SMOTEENN
- unit-testing - kotlin 中的单元测试无法返回值
- flutter - 有没有办法在不使用 dart 循环的情况下找到两个列表之间的唯一值
- python - 如何在 django 中使用模型表单编辑对象?
- google-cloud-platform - 尝试在 gcp 上连接到 SQL Server?
- javascript - 在javascript画布中的2D上下文上实现撤消/重做的多个画布的缺点?
- angular - 为什么这个 ngif 不能与布尔值一起正常工作?