未为 DI/IoC 设置 StructureMap 和对象
StructureMap and objects not setup for DI/IoC
我有一种情况,我创建了一个工厂方法来创建一个对象。但是,该对象具有需要在创建对象之前执行的样板代码。修复那部分设计超出了这个问题的范围。
此外,创建对象时,屏幕上的状态显示也会更新。这要求此状态显示在创建此对象之前实例化并可见,并且应用程序在创建此对象之前处于 运行 状态。它作为依赖项传递给工厂。
我正在使用 StructureMap v3.1.4.143。
所以,这就是我在正常世界(IoC 之前)所做的事情:
GraphicsInterface GetGraphics()
{
VideoDevicesList.GetVideoDevices();
// Some logic here to determine the device to use...
// Also, a status display is being updated to inform the user of
// what's happening at this point.
VideoDevice device = ...;
// The second parameter is a constant value, but the first is not.
return new GraphicsInterface(device, featureLevels.FL5);
}
看起来很简单,但理想情况下我希望能够通过注入传递该图形对象,因为很多地方都需要它。
因此,在结构图中,我创建了一个工厂函数来执行上述操作。然而这让我很伤心。
new Container(obj =>
{
// This is passed to the object that depends on it.
// I've just left it out for brevity.
// It'd go something like: _graphics = _getGraphicsFactory();
// where _getGraphicsFactory is the factory function below.
For<Func<IStatusDisplay, GraphicsInterface>>
.Use<Func<IStatusDisplay, GraphicsInterface>>(GetGraphics);
}
仅此提示我未注册 GraphicsInterface 的错误。很好,我应该能够注册 GraphicsInterface 对象。除了我不能注册 GraphicsInterface 因为构造函数需要两个参数,其中一个 must 在创建对象之前被查询并且只能通过上面的 GetVideoDevices 方法设置并且似乎是 StructureMap尝试在我调用 _getGraphicsFactory() 时为我创建对象(这很奇怪,我希望它执行我的函数来创建对象)。
我什至尝试在我的 GetVideoDevices 方法中这样调用 GetInstance:
_container
.With<VideoDevice>(device)
.With<FeatureLevel>(FeatureLevel.FL5)
.GetInstance<Graphics>();
但是没有骰子...
那么,有没有人知道我如何让它发挥作用?
每当您绞尽脑汁想弄清楚如何在运行时创建实例时,您需要退后一步,寻找适合该问题的设计模式。 DI 用于组合 应用程序,但控制运行时行为应该是应用程序设计的一部分——也就是说,在 应用程序之后运行的部分是组成.
在这种特殊情况下,Abstract Factory 会很合适。它允许您将组合服务(通过构造函数注入的服务)与运行时服务(作为方法参数传递的服务)分开。
但是,您应该限制工厂只做一件事——创建运行时实例。所有其他工作都应该是其他服务的一部分。这为您提供了一种将运行时对象注入服务的简洁方法,并且仍然允许独立于此步骤测试服务行为。
public interface IGraphicsFactory
{
GraphicsInterface Create(VideoDevice device);
void Release(GraphicsInterface graphicsInterface);
}
public class GraphicsFactory : IGraphicsFactory
{
private readonly FeatureLevel featureLevel;
// Parameters injected are done so by the DI container
public GraphicsFactory(FeatureLevel featureLevel)
{
this.featureLevel = featureLevel;
}
// Parameters passed are part of the application runtime state
public GraphicsInterface Create(VideoDevice device)
{
return new GraphicsInterface(device, this.featureLevel);
}
// Method for releasing disposable dependencies (if any)
public void Release(GraphicsInterface graphicsInterface)
{
var disposable = graphicsInterface as IDisposable;
if (disposable != null)
disposable.Dispose();
}
}
然后可以在应用程序组合期间将您的工厂提供给服务,并且可以在运行时创建 GraphicsInterface 的运行时实例。根据您的要求,这可以通过将其注入多个服务的构造函数来轻松地在多个位置完成。
public class SomeService : ISomeService
{
private readonly IGraphicsFactory graphicsFactory;
public SomeService(IGraphicsFactory graphicsFactory)
{
if (graphicsFactory == null)
throw new ArgumentNullException("graphicsFactory")
this.graphicsFactory = graphicsFactory;
}
public void DoSomething()
{
// Get video device here. It will likely be best to
// delegate that to another specialized service
// that is injected into this class.
VideoDevice device = ...;
var graphics = this.graphicsFactory.Create(device);
try
{
// Do something with graphics
}
finally
{
this.graphicsFactory.Release(graphics);
}
}
}
至于选择要使用的设备,这可以通过另一个抽象工厂来完成,或者如果它是经常做的事情,您可以使用 Strategy Pattern 在组合时加载所有选项时间,然后在运行时有选择地选择设备。或者,如果您的设备是一次性的,您可以制定抽象工厂策略或寻求一些更高级的设计模式来清理它们。
如果它还没有合适的可以注入(和交换)的具有您所追求的所有成员,您也可以考虑使用适配器模式为 GraphicsInterface 创建抽象。
public interface IGraphicsInterfaceAdapter
{
// Extract all public properties of GraphicsInteface and define them here.
}
public class GraphicsInterfaceAdapter : IGraphicsInterfaceAdapter
{
public GraphicsInterfaceAdapter(VideoDevice device, FeatureLevel featureLevel)
: base(device, featureLevel)
{
}
}
我有一种情况,我创建了一个工厂方法来创建一个对象。但是,该对象具有需要在创建对象之前执行的样板代码。修复那部分设计超出了这个问题的范围。
此外,创建对象时,屏幕上的状态显示也会更新。这要求此状态显示在创建此对象之前实例化并可见,并且应用程序在创建此对象之前处于 运行 状态。它作为依赖项传递给工厂。
我正在使用 StructureMap v3.1.4.143。
所以,这就是我在正常世界(IoC 之前)所做的事情:
GraphicsInterface GetGraphics()
{
VideoDevicesList.GetVideoDevices();
// Some logic here to determine the device to use...
// Also, a status display is being updated to inform the user of
// what's happening at this point.
VideoDevice device = ...;
// The second parameter is a constant value, but the first is not.
return new GraphicsInterface(device, featureLevels.FL5);
}
看起来很简单,但理想情况下我希望能够通过注入传递该图形对象,因为很多地方都需要它。
因此,在结构图中,我创建了一个工厂函数来执行上述操作。然而这让我很伤心。
new Container(obj =>
{
// This is passed to the object that depends on it.
// I've just left it out for brevity.
// It'd go something like: _graphics = _getGraphicsFactory();
// where _getGraphicsFactory is the factory function below.
For<Func<IStatusDisplay, GraphicsInterface>>
.Use<Func<IStatusDisplay, GraphicsInterface>>(GetGraphics);
}
仅此提示我未注册 GraphicsInterface 的错误。很好,我应该能够注册 GraphicsInterface 对象。除了我不能注册 GraphicsInterface 因为构造函数需要两个参数,其中一个 must 在创建对象之前被查询并且只能通过上面的 GetVideoDevices 方法设置并且似乎是 StructureMap尝试在我调用 _getGraphicsFactory() 时为我创建对象(这很奇怪,我希望它执行我的函数来创建对象)。
我什至尝试在我的 GetVideoDevices 方法中这样调用 GetInstance:
_container
.With<VideoDevice>(device)
.With<FeatureLevel>(FeatureLevel.FL5)
.GetInstance<Graphics>();
但是没有骰子...
那么,有没有人知道我如何让它发挥作用?
每当您绞尽脑汁想弄清楚如何在运行时创建实例时,您需要退后一步,寻找适合该问题的设计模式。 DI 用于组合 应用程序,但控制运行时行为应该是应用程序设计的一部分——也就是说,在 应用程序之后运行的部分是组成.
在这种特殊情况下,Abstract Factory 会很合适。它允许您将组合服务(通过构造函数注入的服务)与运行时服务(作为方法参数传递的服务)分开。
但是,您应该限制工厂只做一件事——创建运行时实例。所有其他工作都应该是其他服务的一部分。这为您提供了一种将运行时对象注入服务的简洁方法,并且仍然允许独立于此步骤测试服务行为。
public interface IGraphicsFactory
{
GraphicsInterface Create(VideoDevice device);
void Release(GraphicsInterface graphicsInterface);
}
public class GraphicsFactory : IGraphicsFactory
{
private readonly FeatureLevel featureLevel;
// Parameters injected are done so by the DI container
public GraphicsFactory(FeatureLevel featureLevel)
{
this.featureLevel = featureLevel;
}
// Parameters passed are part of the application runtime state
public GraphicsInterface Create(VideoDevice device)
{
return new GraphicsInterface(device, this.featureLevel);
}
// Method for releasing disposable dependencies (if any)
public void Release(GraphicsInterface graphicsInterface)
{
var disposable = graphicsInterface as IDisposable;
if (disposable != null)
disposable.Dispose();
}
}
然后可以在应用程序组合期间将您的工厂提供给服务,并且可以在运行时创建 GraphicsInterface 的运行时实例。根据您的要求,这可以通过将其注入多个服务的构造函数来轻松地在多个位置完成。
public class SomeService : ISomeService
{
private readonly IGraphicsFactory graphicsFactory;
public SomeService(IGraphicsFactory graphicsFactory)
{
if (graphicsFactory == null)
throw new ArgumentNullException("graphicsFactory")
this.graphicsFactory = graphicsFactory;
}
public void DoSomething()
{
// Get video device here. It will likely be best to
// delegate that to another specialized service
// that is injected into this class.
VideoDevice device = ...;
var graphics = this.graphicsFactory.Create(device);
try
{
// Do something with graphics
}
finally
{
this.graphicsFactory.Release(graphics);
}
}
}
至于选择要使用的设备,这可以通过另一个抽象工厂来完成,或者如果它是经常做的事情,您可以使用 Strategy Pattern 在组合时加载所有选项时间,然后在运行时有选择地选择设备。或者,如果您的设备是一次性的,您可以制定抽象工厂策略或寻求一些更高级的设计模式来清理它们。
如果它还没有合适的可以注入(和交换)的具有您所追求的所有成员,您也可以考虑使用适配器模式为 GraphicsInterface 创建抽象。
public interface IGraphicsInterfaceAdapter
{
// Extract all public properties of GraphicsInteface and define them here.
}
public class GraphicsInterfaceAdapter : IGraphicsInterfaceAdapter
{
public GraphicsInterfaceAdapter(VideoDevice device, FeatureLevel featureLevel)
: base(device, featureLevel)
{
}
}