泛型类的自动注册



我正试图用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<字符串>gt;可以找到。在ErrorReproduction。测验ErrorReproduction/Test.cs:line 45 中的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);

RegisterXXX(Type, Assembly[])的XML文档声明了以下内容(强调矿):

在给定集中注册所有具体、非泛型、公共和内部类型组件

换句话说,默认情况下,只注册非泛型类型;您的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 }));

最新更新