团结汽车工厂与params
我正在试图找出正确的方法来注入一个需要参数的自动工厂,或者即使Unity可以实现这一点。
例如,我知道我可以这样做:
public class TestLog { private Func logFactory; public TestLog(Func logFactory) { this.logFactory = logFactory; } public ILog CreateLog() { return logFactory(); } } Container.RegisterType(); TestLog test = Container.Resolve(); ILog log = test.CreateLog();
现在我希望能做的是:
public class TestLog { private Func logFactory; public TestLog(Func logFactory) { this.logFactory = logFactory; } public ILog CreateLog(string name) { return logFactory(name); } } Container.RegisterType(); TestLog test = Container.Resolve(); ILog log = test.CreateLog("Test Name");
不幸的是,这不起作用。 我可以看到你如何设置自定义工厂来在Unity中创建实例,似乎无法为这个例子提供任何明确的例子。
显然,我可以创建自己的工厂,但我正在寻找一种优雅的方式在Unity中以最少的代码执行此操作。
很抱歉成为那些讨厌回答自己问题的人之一,但我想出来了。
public class TestLog { private Func logFactory; public TestLog(Func logFactory) { this.logFactory = logFactory; } public ILog CreateLog(string name) { return logFactory(name); } } Container.RegisterType>( new InjectionFactory(c => new Func(name => new Log(name)) )); TestLog test = Container.Resolve(); ILog log = test.CreateLog("Test Name");
@TheCodeKing的答案工作正常,但在大多数(可能全部?)案例中可以缩短为以下内容:
Container.RegisterInstance>(name => new Log(name));
(注意我正在使用RegisterInstance()
而不是RegisterType()
)
由于Func<>
实现已经是一种工厂,因此通常不需要将它包装在InjectionFactory
。 它只能确保Func
每个分辨率都是一个新实例,我真的不能想到需要这个的场景。
如果您正在寻找完全类型的工厂接口(例如,允许XML文档和参数名称),您可以使用我创建的NuGet包 ,您可以通过为工厂定义接口,然后关联它来利用它它与您想要实例化的具体类型。
代码存在于GitHub中: https : //github.com/PombeirP/FactoryGenerator
Autofac具有参数化实例化,以处理需要带参数的自动出厂的场景。
虽然Unity不支持开箱即用,但可以实现一个类似于Autofac的扩展。
一个无耻的插件:我实现了这样的扩展 – 参数化自动工厂 。
它可以以类似于此的方式使用:
public class Log { public void Info(string info) { /* ... */ } public void Warn(string info) { /* ... */ } public void Error(string info) { /* ... */ } } public class LogConsumer { private readonly Log _log; private readonly string _consumerName; public LogConsumer(Log log, string consumerName) { _log = log; _consumerName = consumerName; } public void Frobnicate() => _log.Info($"{nameof(Frobnicate)} called on {_consumerName}"); } var container = new UnityContainer() .AddNewExtension(); var logConsumerFactory = container.Resolve>(); var gadget = logConsumerFactory("Gadget"); gadget.Frobnicate();
请注意:
-
Func
是从container
解析的,但它没有在任何地方注册 – 它是自动生成的。 -
Func
仅为LogConsumer
的构造函数提供string consumerName
参数。 因此,从容器中解析Log log
参数。 如果auto-factory func看起来像这个Func
,那么LogConsumer
的构造函数的所有参数都将通过自动工厂提供。
基本上,扩展程序的工作方式如下:
- 它在Unity的管道中注册了一个所谓的
BuilderStrategy
。 - 只要Unity要构建类型的实例,就会调用此策略。
- 如果要构建的类型尚未明确注册并且是带参数的
Func
,则扩展将拦截实例构建过程。 - 现在我们只需要动态创建给定类型的
Func
,它从容器中解析其返回类型,并将Func
的参数作为ResolverOverride
集合传递给IUnityContainer.Resolve
方法。