本文介绍了StructureMap和对象没有设置为DI /国际奥委会的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有,我已经创建了一个工厂方法来创建一个对象的情况。然而,对象创建对象之前,需要执行样板代码。固定设计的一部分超出范围为这个问题。

I have a situation where I've created a factory method to create an object. However, the object has boilerplate code that needs execution before the object is created. Fixing that part of the design is out of scope for this question.

此外,在创建对象时,状态更新显示在屏​​幕上。这要求这种状态显示之前被实例化并且是可见和应用处于运行状态创建该对象之前。它被传递到厂家的依赖。

Also, when the object is created, a status display is updated on screen. This requires that this status display be instantiated before and be visible and the application be in a running state before creating this object. It is passed to the factory as a dependency.

我使用StructureMap的v3.1.4.143。

I'm using v3.1.4.143 of StructureMap.

所以,在这里就是我想要在正常的世界(预IOC)做:

So, here's what I'd be doing in the normal world (pre-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);
}



看起来很简单,但理想的我希望能够传递因为它会在许多景点需要的图形通过注射对象周围。

Seems simple enough, but ideally I'd like to be able to pass that graphics object around via injection as it'll be needed in many spots.

所以,在结构图,我创建了一个工厂函数来完成上面。但它给我的悲伤。

So, in structure map, I created a factory function to do the above. However it's giving me grief.

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必须的要创建对象之前查询,只能通过上面的方法GetVideoDevices成立,它似乎StructureMap尝试创建对我来说,对象当我打电话_getGraphicsFactory()(这是奇怪的,我会,预计它来执行我的函数来创建对象)。

Only this gives me an error about GraphicsInterface not being registered. That's fine, I should be able to register the GraphicsInterface object. Except that I can't register GraphicsInterface because the constructor requires two parameters, one of which must be queried before creating the object and can only be set up via the GetVideoDevices method above and it seems StructureMap tries to create the object for me when I call _getGraphicsFactory() (which is weird, I would have it expected it to execute my function to create the object).

我甚至尝试调用的GetInstance这样我GetVideoDevices方法里面:

I tried even calling GetInstance like this inside of my GetVideoDevices method:

_container
    .With<VideoDevice>(device)
    .With<FeatureLevel>(FeatureLevel.FL5)
    .GetInstance<Graphics>();



但没有骰子...

But no dice...

因此,没有人对我怎么会得到这个工作的想法?

So, does anyone have an idea on how I'd get this to work?

推荐答案

每当你抓你的头试图找出如何在运行时创建实例,你需要退后一步,寻找一个设计图案,将适合的问题。 DI是指用于组成的应用,但控制运行时行为应该是应用设计的一部分 - 即,在运行的的应用程序是由部分

Whenever you are scratching your head trying to work out how to create instances at runtime, you need to step back and look for a design pattern that will fit the problem. DI is meant for composing applications, but controlling runtime behavior should be part of the application design - that is, the part that runs after the application is composed.

在这种特殊情况下,将是一个不错的选择。它可以让你从运行服务组成的服务(通过构造函数注入)(那些作为方法参数传递)中分离出来。

In this particular case, Abstract Factory would be a good fit. It allows you to separate the composed services (those injected through the constructor) from runtime services (those passed as method parameters).

然而,你应该限制一家工厂做恰好一件事 - 创建运行时实例。所有其他的工作应该是其他服务的一部分。这给你一个干净的方式注入一个运行时对象为您服务,并仍然允许服务行为进行独立这一步的测试。

However, you should restrict a factory to doing exactly one thing - creating the runtime instance. All other work should be part of other services. This gives you a clean way to inject a runtime object into your service and still allow the service behavior to be tested independently of this step.

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的组合物,和运行时实例可在运行时被创建。按您的要求,这可以很容易地在多点注射入多种业务的构造完成。

Your factory can then be supplied to a service during application composition, and runtime instances of GraphicsInterface can be created at runtime. As per your requirement, this can easily be done in multiple spots by injecting it into the constructors of multiple services.

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);
        }
    }
}



至于选择装置使用,即既可以与另一个抽象工厂完成,或者如果它是什么,往往是做,你可以使用的来加载所有的在合成时间的选项,然后选择性地选择在运行时该设备。或者,如果你的设备是一次性的,你可以把抽象工厂的战略还是看一些更先进的设计模式,以清除它们。

As for selecting the device to use, that could either be done with another Abstract Factory, or if it is something that is done often, you could use a Strategy Pattern to load all of the options at composition time, and then selectively choose the device at runtime. Or, if your devices are disposable, you could make a Strategy of Abstract Factories or look to some more advanced design pattern to clean them up.

您也可以考虑使用适配器模式创建GraphicsInterface的抽象,如果它已经没有合适的可以注入(和交换),有所有你所追求的成员。

You might also consider using an adapter pattern to create an abstraction for GraphicsInterface if it doesn't already have a suitable that can be injected (and swapped) that has all of the members you are after.

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和对象没有设置为DI /国际奥委会的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-06 01:22