在通过Factory创建实例时隔离实例(以及实例依赖项)的依赖项

时间:2014-06-13 14:22:54

标签: c# dependency-injection ninject ninject-extensions

编辑:在解决我的问题后,我已经大大清理了这个问题,包括更改标题。

我有一个MessageChannel接口,它定义了(不出所料)我的类可用于将消息推送给最终用户的通道。

通常,此MessageChannel是Singleton,并绑定到实现MessageChannel接口的ViewModel。从本质上讲,我的应用程序顶部有一个位置,用于显示给用户的消息。到目前为止,它的效果非常好。

此MessageChannel用于很多地方,其中一个位于我设置的某些操作类中。

我现在需要一个LOCAL MessageChannel,这些在一些缩小范围内发布的消息会发布到本地MessageChannel而不是全局消息。

这意味着我需要能够创建ViewModel的实例(通过Factory),以便该特定实例具有自己的MessageChannel实例,并且为注入该ViewModel的所有依赖项共享MessageChannel实例(和他们的依赖等等。)

一些类来说明。我稍微简化了一些事情,我的消息不仅仅是字符串:

using Ninject;
using Ninject.Extensions.Factory;

public interface MessageChannel
{
    void PostMessage(string message);
}

public class MessageChannelViewModel : MessageChannel
{
    public string Message { get; set; }

    public void PostMessage(string message)
    {
        Message = message;
    }
}

public interface Operation
{
    void Do();
}

public interface OperationFactory
{
    Operation Create();
}

public class DefaultOperation : Operation
{
    public DefaultOperation(MessageChannel userMessages)
    {
        _UserMessages = userMessages;
    }

    private readonly MessageChannel _UserMessages;

    public void Do()
    {
        // Do something.
        _UserMessages.PostMessage("Success!");
    }
}

public interface IsolatedViewModel
{
    MessageChannelViewModel LocalMessages { get; }
}

public interface IsolatedViewModelFactory
{
    IsolatedViewModel Create();
}

public class DefaultIsolatedViewModel : IsolatedViewModel
{
    public IsolatedViewModel(MessageChannelViewModel localMessages, OperationFactory opFactory)
    {
        _OpFactory = opFactory;
        LocalMessages = localMessages;
    }

    private readonly OperationFactory _OpFactory;

    public MessageChannelViewModel LocalMessages { get; private set; }
}



public class Module : NinjectModule
{
    public override void Load()
    {
        Bind<MessageChannel, MessageChannelViewModel>().To<MessageChannelViewModel>().InSingletonScope();

        Bind<Operation>().To<DefaultOperation>();
        Bind<OperationFactory>().ToFactory();

        Bind<IsolatedViewModel>().To<DefaultIsolatedViewModel>();
        Bind<IsolatedViewModelFactory>().ToFactory();

        // Something to make it so the IsolatedViewModel DOESNT get the Singleton
        // instance of the MessageChannelViewModel, and instead gets once of its own
        // AND so the Operations created by the OperationFactory injected into the
        // IsolatedViewModel get the SAME MessageChannel, so messages being posted
        // from any place in the IsolatedViewModel's dependencies are shown only\
        // locally.
    }
}

我尝试过NamedScope扩展,但我无法按照我的意愿去做。

2 个答案:

答案 0 :(得分:1)

我认为你可以尝试使用 The Ninject Context Preservation Extension ,它增加了对调用内核解析请求的工厂的上下文的记录(以及可用于上下文绑定规则)的支持。

这使您可以为Bindings添加上下文条件。

答案 1 :(得分:1)

我最终使用了Ninject.Extensions.ContextPreservation和Ninject.Extensions.NamedScope的组合来完成我想要的。

完成的示例模块如下所示:

public class Module : NinjectModule
{
    public override void Load()
    {
        Bind<MessageChannel, MessageChannelViewModel>().To<MessageChannelViewModel>().InSingletonScope();

        Bind<Operation>().To<DefaultOperation>();
        Bind<OperationFactory>().ToFactory();

        var uniqueName = "UNIQUE";
        Bind<IsolatedViewModel>()
            .To<DefaultIsolatedViewModel>()
            .Named(uniqueName)
            .DefinesNamedScope(uniqueName);

        Bind<MessageChannel, MessageChannelViewModel>().To<MessageChannelViewModel>()
            .WhenAnyAncestorNamed(uniqueName)
            .InNamedScope(uniqueName);

        Bind<IsolatedViewModelFactory>().ToFactory();
    }
}

Theres的两个部分。

  1. 您需要ContextPreservation扩展,以根据解析对象实例时可用的上下文选择正确的绑定。在这种情况下,我使用了一个名称作为上下文,这意味着在解析IsolatedViewModel所需的任何依赖项的MessageChannel依赖项时,将使用我的特殊MessageChannel绑定。
  2. 我需要NamedScope扩展来确保在每个IsolatedViewModel实例下只创建了一个MessageChannel实例(即该实例是为了IsolatedViewModel及其所有依赖项共享的。)
  3. 其他一些需要注意的事项:

    • 如果您正在使用任何ToMethod绑定并且在方法中使用内核,则需要确保使用ContextPreservingGet,否则您将丢失上下文并且不会选择正确的绑定。< / LI>
    • 您必须仔细查看绑定并仔细检查任何Singleton绑定,因为如果您的隔离类的任何依赖关系绑定在Singleton范围内,并且它们依赖于MessageChannel(例如)不会像你想要的那样去工作。因此,我不得不删除一些Singleton范围的绑定(可能更好)。