Ulf*_*edt 10 .net c# factory dependency-injection unity-container
假设我有一个Simple Factory(SimpleProductFactory),它使用条件参数来确定如何创建Product如下:
public static class SimpleProductFactory
{
public static Product MakeProduct(Condition condition)
{
Product product;
switch(condition)
{
case Condition.caseA:
product = new ProductA();
// Other product setup code
break;
case Condition.caseA2:
product = new ProductA();
// Yet other product setup code
break;
case Condition.caseB:
product = new ProductB();
// Other product setup code
break;
}
return product;
}
}
Run Code Online (Sandbox Code Playgroud)
某个客户端使用此工厂来处理包含以下条件的运行时数据:
public class SomeClient
{
// ...
public void HandleRuntimeData(RuntimeData runtimeData)
{
Product product = SimpleProductFactory.MakeProduct(runtimeData.Condition);
// use product...
}
// ...
}
public class RuntimeData
{
public Condition Condition { get; set; }
// ...
}
Run Code Online (Sandbox Code Playgroud)
如何使用Unity 2.0实现相同的构造行为?
重要的部分是condition(Condition)确定如何创建和设置Product,条件只在运行时已知,并且每个MakeProduct(...)调用都不同.("其他产品设置代码"处理一些委托内容,但也可以处理其他初始化,并且需要成为构造的一部分.)
如何进行容器注册Product(或IProduct接口)?
我应该使用InjectionFactory建筑吗?我怎么做?
// How do I do this?
container.RegisterType<Product>(???)
Run Code Online (Sandbox Code Playgroud)
为了能够在客户端代码中提供条件,我需要做什么?
Naïve客户端代码(来自之前的编辑)突出显示最后一个问题,解释了几个答案的措辞:
public class SomeClient
{
// ...
public void HandleRuntimeData(RuntimeData runtimeData)
{
// I would like to do something like this,
// where the runtimeData.Condition determines the product setup.
// (Note that using the container like this isn't DI...)
Product product = container.Resolve<Product>(runtimeData.Condition);
// use product...
}
// ...
}
Run Code Online (Sandbox Code Playgroud)
(我在Stackoverflow上已经阅读了很多类似的问题,但是根据我的需要,他们无法满足他们的需求.)
您不应该使用容器来做出这样的运行时决定.而是通过容器将工厂注入客户端.如果工厂需要容器的附属物,请在创建时将它们注入工厂.
将您的工厂更改为实际对象,而不是仅仅作为静态方法的容器,并注入它.
您不应以任何方式在类中注入或使用容器.这包括使用参数.这样做的原因是,这样做会将代码绑定到容器.如果您必须实现另一个容器甚至是新版本,那么您将需要做大量的工作.
但是,对于您描述Unity(以及其他一些注入框架)的情况,该功能称为"自动工厂".它使用.NET Func <TResult>委托.这是一个.NET功能,因此它不会将您的类与Unity绑定.
这是如何使用它,首先注册您的服务.不要用a注册,ContainerControlledLifetimeManager否则每次都会获得相同的实例.
unity.RegisterType<IOpenFileService, OpenFileService>();
Run Code Online (Sandbox Code Playgroud)
然后为它注册一个自动工厂.
unity.RegisterType<Func<IOpenFileService>>();
Run Code Online (Sandbox Code Playgroud)
然后可以将其注入任何需要它的类中.
unity.RegisterType<ViewModelBase, OptionsFileLocationsViewModel>(
new InjectionConstructor(new ResolvedParameter<Func<IOpenFileService>>());
Run Code Online (Sandbox Code Playgroud)
如果你现在解析OptionsFileLocationsViewModel它的一个实例,就不会注入一个IOpenFileService带有函数的实例,如果调用它将返回一个实例IOpenFileService.
private readonly Func<IOpenFileService> openFileServiceFactory;
private string SelectFile(string initialDirectory)
{
var openFileService = this.openFileServiceFactory();
if (Directory.Exists(initialDirectory))
{
openFileService.InitialDirectory = initialDirectory;
}
else
{
openFileService.InitialDirectory =
System.Environment.GetFolderPath(System.Environment.SpecialFolder.Desktop);
}
bool? result = openFileService.ShowDialog();
if (result.HasValue && result.Value)
{
return openFileService.FileName;
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
我希望这个简短的解释会激励你解决你的问题.
| 归档时间: |
|
| 查看次数: |
9517 次 |
| 最近记录: |