StructureMap:创建为瞬态(每个请求)不起作用

时间:2016-03-27 11:41:30

标签: c# dependency-injection ioc-container structuremap

我试图解决IoC问题,起初看起来很容易,但事实证明这是一个痛苦的问题:-P

我有一个重量级的主类,必须只初始化一次,所以它被标记为Singleton。但是这个类使用的子类必须为每个请求创建一次,因此它被标记为Transient:

public class MyRegistry : Registry
{
    public MyRegistry()
    {
        For<IMainClass>()
            .Singleton()
            .Use(ctx => new MainClass(() => ctx.GetInstance<ISubClass>()));

        For<ISubClass>()
            .Transient()
            .Use(ctx => CreateNewInstanceOfSubClass());
    }

    private ISubClass CreateNewInstanceOfSubClass()
    {
        return new SubClass();
    }
}

public interface ISubClass
{ }

public class SubClass : ISubClass
{ }

public interface IMainClass
{ }

public class MainClass : IMainClass
{
    private readonly Func<ISubClass> _subClassProvider;

    public MainClass(Func<ISubClass> subClassProvider)
    {
        _subClassProvider = subClassProvider;
    }

    public void DoStuff()
    {
        var requestSpecificInstanceOfSubClass = _subClassProvider();

        // ...
    }
}

如您所见,我将lambda传递给MainClass的构造函数,该构造函数用于获取ISubClass的实例。在调试期间,我确实可以看到每次ctx.GetInstance<ISubClass>()需要MainClass实例时都会执行SubClass。但令我惊讶的是,SubClass仅作为单身创建一次,而不是为每个请求创建。

但是,当我直接从代码中的某个地方调用container.GetInstance<ISubClass>()时,行为完全符合要求。 SubClass为每个请求创建一次且仅创建一次。

我不太确定,但我猜问题来自传递给lambda的上下文对象,它是单例(?)的上下文。但我真的不知道如何在这里得到理想的行为!?

我希望你能帮助我解决这个问题。谢谢你的回答。

此致 但丁

3 个答案:

答案 0 :(得分:0)

这很正常。

因为您正在解决Mainton中的ISubclass,它是单例。

当Main Class解决时,它将获得一个Subclass并且它们将共存(它们必须因为main是singlenton)。

当你解决时,你应该检查第一个父生命周期,如果它是单身,你对每个请求或每个依赖关系无关紧要,它将与单身生活在一起。

答案 1 :(得分:0)

您似乎需要重新设计一下设计。为了避免使用captive dependencies,您需要为图的根对象提供比其任何依赖项更短(或相等)的生命周期。

一种选择是建立第3课来管理MainClassSubClass之间的互动。

接口

public interface IInteractionManager
{ 
    void DoStuff();
}

public interface IMainClass
{ 
    void DoStuff(ISubclass subclass);
}

public interface ISubClass
{ }

public class InteractionManager : IInteractionManager
{
    private readonly IMainClass mainClass;
    private readonly ISubClass subClass;

    public InteractionManager(
        IMainClass mainClass,
        ISubClass subClass)
    {
        this.mainClass = mainClass;
        this.subClass = subClass;
    }

    public void DoStuff()
    {
        this.mainClass.DoStuff(this.subClass);
    }
}

public class MainClass : IMainClass
{
    public void DoStuff(ISubclass subclass)
    {
        // do something with transient subclass
    }
}

public class SubClass : ISubClass
{ }

注册表

public class MyRegistry : Registry
{
    public MyRegistry()
    {
        // The root of the object graph is transient...
        For<IInteractionManager>()
            .Transient()
            .Use<InteractionManager>();

        // ...therefore, it can have transient dependencies...
        For<ISubClass>()
            .Transient()
            .Use<SubClass>();

        // ...and singleton dependencies.
        For<IMainClass>()
            .Singleton()
            .Use<MainClass>();
    }
}

答案 2 :(得分:0)

如果您确实需要 #lineForUrl a #title-font{ word-wrap: break-word; } @media screen and (max-width: 480px) { #footer { padding: 2em 1em 0.1em 1em; } #lineForUrl a #title-font { max-width: 100%; overflow: visible; display: inline-block; font-size: smaller; } } 成为长期存在的对象,但每个请求使用一个新的MainClass对象,您可以:

1。)将Func的自定义实例注册到容器或MainClass本身的注册,该注册委托给根 Container 本身。请记住,您也可以使用自动布线,因此您不必全部内联。

2.。)将IContainer本身注入MainClass并将其用作服务定位器,以便在每次请求期间懒惰地检索新的ISubClass。

使用IContext的方式不起作用,因为IContext与原始请求相关联。 StructureMap中的“瞬态”实际上意味着“每个请求”,因此当您将Func注入到委托给原始IContext的单例中时,每次都会获得完全相同的ISubClass。有关生命周期的详细信息,请参阅http://structuremap.github.io/object-lifecycle/

我是SM的作者btw。