IoC容器对象作用域

时间:2009-11-19 13:42:02

标签: c# ioc-container

我有兴趣在我的项目中实现一个IoC容器,但是我还没有看到一个可以满足我需要的例子。

在这种情况下,我的应用程序是在WPF中构建的,并使用MVVM模式为红外视频格式创建播放器。在这种格式中,每个视频实际上由多个“子帧”组成(将其视为同时以多个快门速度捕获以增加数据的动态范围),每个子帧都显示在TabControl中。我想使用IoC容器来帮助我为每个选项卡创建ViewModel,但我有两个问题。

  1. 我需要一种方法来传递代表我正在创建ViewModel的子帧的对象,因此至少有一个ViewModel的依赖项不能由IoC容器创建,因为它已经存在。

  2. 我在视图中有用户控件,用于具有自己的ViewModel的子帧,因此这些ViewModel也需要由IoC容器创建。这个问题是虽然控件(和它们的ViewModel)有不同的关注点,但它们并不是完全独立的,所以它们使用了一些协调对象。不幸的是,在我看到的所有示例中,你可以让你的IoC容器创建一个新的依赖实例或者有一个单例,但我需要的是在我创建子帧ViewModel的受控范围内的单个实例

  3. 这是很多文字,所以这里有一些代码可以显示我正在做什么以及我想做什么。

    我现在拥有的

    在开放电影代码中:

    foreach (var subframe in movieFile)
    {
        // Subframes is the ObservableCollection that the TabControl is bound to
        Subframes.Add(new SubframeViewModel(subframe));
    }
    

    在SubframeViewModel中:

    public SubframeViewModel(ISubframe subframe)
    {
        _subframe = subframe;
    
        // FrameController tracks the current frame number and fires an event 
        // when it changes
        var frameController = new FrameController(subframe); 
    
        // ImageViewModel represents the actual movie image. Uses FrameController
        // to know when to raise PropertyChanged for the property that represents
        // the image
        ImageViewModel = new ImageViewModel(subframe, frameController);
    
        // FrameControlViewModel represents the playback controls.  Uses
        // FrameController to implement actions
        // Play, Pause, Jump to frame, Jump to time...
        FrameControlViewModel = new FrameControlViewModel(subframe, frameController);
    }
    

    我希望在不更改现有语义的情况下获得

    在开放电影代码中:

    foreach (var subframe in movieFile)
    {
        Subframes.Add(container.Resolve<SubframeViewModel>());
    }
    

    在SubframeViewModel中:

    public SubframeViewModel(ISubframe subframe, ImageViewModel imageModel, 
                                FrameControlViewModel frameModel)
    {
        _subframe = subframe;
    
        ImageViewModel = imageModel;
    
        FrameControlViewModel = frameModel;
    }
    

    实际上,涉及更多协调和ViewModel对象,但模式是相同的。也就是说,我想你可以在这里看到为什么我对IoC容器感兴趣。

    我认为我的情景应该相当普遍,但我不确定,我不想浪费时间试图将方形钉子放入圆孔中,所以这是我的问题。任何/所有IoC容器都可以这样做吗?如果没有,你能否指出我将改进我的代码并使IoC工作的重构?

2 个答案:

答案 0 :(得分:1)

Autofac绝对可以满足您的需求 - 显式提供的参数可以与容器自动装配的参数组合使用:

vm = container.Resolve<SubFrameViewModel>(new NamedParameter("subframe", subframe));

(也可以按类型而不是名称进行匹配。)

你甚至可以让容器将一个Func或自定义委托注入到调用组件中,这样就不需要容器依赖(即调用Resolve):

Func<ISubFrame, SubFrameViewModel> _vmFactory; // Injected
vm = _vmFactory(subframe);

有关后者的信息,请参阅http://code.google.com/p/autofac/wiki/DelegateFactories

尼克

答案 1 :(得分:1)

看起来你想在IoC场景中处理额外的构造函数参数,我看到两个选项:

1 - 创建一个接收子帧的简单构造函数,并将ImageViewModel和FrameControlViewModel公开为公共可设置属性,如下所示:

// assumes frameControlVM and imageVM have been constructed and are valid
foreach (var subframe in movieFile)
{
    var subframeVM = container.Resolve<SubframeViewModel>(subframe);
    subframeVM.ImageVM = imageVM;
    subframeVM.FrameControlVM = frameControlVM ;
    Subframes.Add(subframeVM);
}

2 - 将您需要的参数传递给IoC容器,该容器只是将参数传递给SubframeVM构造函数:

// assumes frameControlVM and imageVM have been constructed and are valid
foreach (var subframe in movieFile)
{
    var subframeVM = container.Resolve<SubframeViewModel>(subframe, imageVM, frameControlVM);
    Subframes.Add(subframeVM);
}

最终选择哪一个取决于您希望SubframeViewModel IoC解析器与其他VM配合的紧密耦合程度。如果您的imageVM和frameControlVMs需要自己的IoC,您可以简单地将它们链接在一起:

// assumes frameControlVM and imageVM have been constructed and are valid
foreach (var subframe in movieFile)
{
    var frameControlVM = container.Resolve<FrameControlViewModel >(subframe);
    var imageVM = container.Resolve<ImageViewModel>(subframe, frameControlVM);
    var subframeVM = container.Resolve<SubframeViewModel>(subframe, imageVM, frameControlVM);
    Subframes.Add(subframeVM);
}