用Unity解析IEnumerable <T>

Mar*_*ann 37 c# ienumerable dependency-injection unity-container

Unity可以自动解决IEnumerable<T>吗?

假设我有一个带有这个构造函数的类:

public CoalescingParserSelector(IEnumerable<IParserBuilder> parserBuilders)
Run Code Online (Sandbox Code Playgroud)

我在容器中配置单个IParserBuilder实例:

container.RegisterType<IParserSelector, CoalescingParserSelector>();
container.RegisterType<IParserBuilder, HelpParserBuilder>();
container.RegisterType<IParserBuilder, SomeOtherParserBuilder>();
Run Code Online (Sandbox Code Playgroud)

我可以在不必实现自定义实现的情况下完成这项工作IEnumerable<IParserBuilder>吗?

var selector = container.Resolve<IParserSelector>();
Run Code Online (Sandbox Code Playgroud)

到目前为止,我还没有以任何简单的方式表达这一点,但我仍然在提升Unity,所以我可能错过了一些东西.

Mar*_*ann 63

事实证明,这实际上非常简单:

container.RegisterType<IEnumerable<IParserBuilder>, IParserBuilder[]>();
Run Code Online (Sandbox Code Playgroud)

Unity 本身可以理解数组,所以我们只需要将枚举映射到相同类型的数组.

  • 此解决方案仅在您为注册命名时才有效!即它不会像OP在他的问题描述中声明的那样起作用!必须更改为`container.RegisterType <IParserBuilder,HelpParserBuilder>("A");`等等... (5认同)
  • 如下所述,如果使用多个实例,您还需要包含唯一的名称.否则List将包含零项:`container.RegisterType <IParserBuilder,HelpParserBuilder>("HelpParserBuilder"); (3认同)

JCa*_*ico 12

@Metro Smurf:你的回答让我走上正轨:Unity无法自动解决IEnumerable<T>依赖关系.

我无法编译您的示例,因为该RegisterType方法不将InjectionConstructor实例作为参数.

另请注意,ResolveAll只有在您注册了多个具有不同名称的类型时,此方法才会起作用,并且此方法不会返回默认(未命名)注册的实例.(我完全不同意这种行为btw).

这对我有用:

container.RegisterType<IParserBuilder, HelpParserBuilder>("HelpParserBuilder");
container.RegisterType<IParserBuilder, SomeOtherParserBuilder>("SomeOtherParserBuilder");
container.RegisterType<IParserSelector, CoalescingParserSelector>();

container.Configure<InjectedMembers>().ConfigureInjectionFor<CoalescingParserSelector>(new InjectionConstructor(container.ResolveAll<IParserBuilder>()));
Run Code Online (Sandbox Code Playgroud)

为了解决单个实例,您还需要添加默认注册,否则调用Resolve<T>()将失败.

此代码使默认注册启用单一分辨率:

container.RegisterType<IParserBuilder, HelpParserBuilder>();
IParserBuilder builder = container.Resolve<IParserBuilder>()
Run Code Online (Sandbox Code Playgroud)


小智 7

如果你想一般支持IEnumerable,那么你可以添加这一行:

_container.RegisterType(typeof(IEnumerable<>), new InjectionFactory((IUnityContainer container, Type type, string name) => container.ResolveAll(type.GetGenericArguments().Single())));
Run Code Online (Sandbox Code Playgroud)

这是他的通用版本

container.RegisterType<IEnumerable<IParserBuilder>, IParserBuilder[]>();
Run Code Online (Sandbox Code Playgroud)


Met*_*urf 6

我相信你需要使用ResolveAll方法并使用一个显式的InjectionConstructor对象,即:

container.RegisterType<IParserBuilder, HelpParserBuilder>();
container.RegisterType<IParserBuilder, SomeOtherParserBuilder>();

var injectedBuilders = new InjectionConstructor(container.ResolveAll<IParserBuilder>());
container.RegisterType<IParserSelector, CoalescingParserSelector>(injectedBuilders);
Run Code Online (Sandbox Code Playgroud)

换句话说,我不认为Unity能够自动解析类型的所有实例,并且知道在具有IEnumerable参数的类上使用构造函数注入,而无需在运行时明确声明InjectionConstructor对象.

虽然我也在学习Unity,但这是我的经验(YMMV).


小智 5

container.RegisterType<IEnumerable<IParserBuilder>, IParserBuilder[]>();
Run Code Online (Sandbox Code Playgroud)

为我工作时请记住,当您向容器注册IParserBuilder类型时,需要一个唯一的名称,否则它将始终是一个空数组.所以使用

container.RegisterType<IParserBuilder, RealParserBuilder>("UniqueName");
Run Code Online (Sandbox Code Playgroud)