如何使用具有“贪婪”构造函数的Scan来使用具有通用未closurestypes的StructureMap

在各种堆栈溢出问题和博客post之间,关于开放式generics和StructureMap的主题有相当多的文档。 不幸的是,我必须错过一些东西,因为我试图使用scan来执行configuration,而具有“贪婪”构造函数的类实现还没有工作。

我希望StructureMap通过引用其实现的接口来获取下一个类的实例。 ToCsvService存在于名为“基础结构”的未引用程序ToCsvServiceIToCsvService存在于名为Core的引用程序IToCsvService 。 正如你可以看到ToCsvService有一个“贪婪的”构造函数。

 public class ToCsvService<TSource> : IToCsvService<TSource> { public ToCsvService(ICollection<TSource> collection) { } } 

我让StructureMap通过ConnectImplementationsToTypesClosing方法了解ToCsvService

 ObjectFactory.Initialize(cfg => { cfg.Scan(scan => { scan.Assembly("Infrastructure"); scan.WithDefaultConventions(); // even with this call StructureMap cannot use ToCsvService // instance of IToCsvService (though wouldn't expect it to) scan.ConnectImplementationsToTypesClosing (typeof(IToCsvService<>)); }); }); 

ObjectFactory.WhatDoIHave()方法看来,StructureMap知道ToCsvService

 PluginType名称说明                                                                                                                          
 -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- --------------------------------
 IToCsvService`1(IToCsvService`1)                                                                                                                                                                                                                                      
范围如下:瞬态                                                                                                                                                                                                                                                                                  
                                       6202a7ee-89a4-4edd-831d-4867b7dd1a7econfiguration实例的Infrastructure.Services.ToCsvService`1,基础结构,版本= 1.0.0.0,文化=中立,PublicKeyToken = null 
                                       Infrastructure.Services.ToCsvService`1,Infrastructure,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null已configuration实例的Infrastructure.Services.ToCsvService`1,基础结构,版本= 1.0.0.0,Culture = neutral,PublicKeyToken = null                   

但是,当我在Controller构造函数中指定IToCsvService<CustomerViewModel> ,会引发exception

结构映射例外代码:202没有为PluginFamily Core.Services.IToCsvService`1 [[UI.Models.MachineForm,UI,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null]],Core,Version = 1.0定义的默认实例。 0.0,Culture = neutral,PublicKeyToken = null

我想这是因为StructureMap不知道该怎么处理“贪婪的” ToCsvService构造函数。 有没有办法让StructureMap能够和这个构造器一起玩呢? 我是否需要从构造函数切换到实例化后才设置collection属性?

问题结构图和genericstypes的细节有点我试图做,但不利用扫描来做到这一点。 Joshua Flanagan提供的答案利用了For(x).Use(y)configuration,如果我没有扫描程序集,这可能会起作用,因为我没有引用ToCsvService

编辑

我想看看是否使用不同的机制让StructureMap识别ToCsvService<>实例会有效果。 它会更改ObjectFactory.WhatDoIHave()报告的内容并抛出一个不同的exception。 这里有一个使用AddAllTypesOf的例子。

 ObjectFactory.Initialize(cfg => { cfg.Scan(scan => { scan.Assembly("Infrastructure"); scan.WithDefaultConventions(); scan.AddAllTypesOf(typeof(IToCsvService<>)); }); }); 

ObjectFactory.WhatDoIHave()使用上面的转储后

 PluginType名称说明                                                                                                                                            
 -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- ------------------
 IToCsvService`1(IToCsvService`1)Infrastructure.Services.ToCsvService`1,Infrastructure,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = nullconfiguration的Infrastructure.Services.ToCsvService`1实例,Infrastructure,Version = 1.0.0.0, Culture = neutral,PublicKeyToken = null                   
范围如下:瞬态

                                      Infrastructure.Services.ToCsvService`1,Infrastructure,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null已configuration实例的Infrastructure.Services.ToCsvService`1,基础结构,版本= 1.0.0.0,Culture = neutral,PublicKeyToken = null                   
 -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- ------------------
 IToCsvService`1(IToCsvService`1)Infrastructure.Services.ToCsvService`1,Infrastructure,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = nullconfiguration的Infrastructure.Services.ToCsvService`1实例,Infrastructure,Version = 1.0.0.0, Culture = neutral,PublicKeyToken = null                   
范围如下:瞬态

                                      Infrastructure.Services.ToCsvService`1,Infrastructure,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null已configuration实例的Infrastructure.Services.ToCsvService`1,基础结构,版本= 1.0.0.0,Culture = neutral,PublicKeyToken = null

有了这个configuration,我抛出了这个exception:

StructureMap Exception Code:202没有为PluginFamily定义的默认实例System.Collections.Generic.ICollection`1 [[UI.Models.MachineForm,UI,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null]],mscorlib,Version = 4.0.0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089

对我来说,exception表明StructureMap知道它需要一个ICollection<MachineForm>实例化ToCsvService但不知道从哪里得到它。 下面是关于使用StructureMap和Constructor setter注入 Jimmy的评论。 但是,如果不添加对基础结构程序集的明确引用,这似乎不可能。

在结构图和generics上有一些相关的Stack Overflow问题

  • 结构图和通用types
  • 在开放genericstypes的结构映射setter注入?
  • 结构图使用扫描function自动注册一般types

有关StructureMap&Generics的博客post

  • 高级结构图:将实现连接到打开的genericstypes
  • 高级结构图:部分closurestypes的自定义注册约定
  • 在StructureMap中打开genericstypes

有没有IToCsvService的具体实现? 或者只是打开typesToCsvService?

ConnectImplementationsToTypesClosing用于将具体的CustomerViewModelToCsvService连接到IToCsvService <>。 如果你想连接打开的类来打开接口,你需要:

 For(typeof(IToCsvService<>)).Use(typeof(ToCsvService<>)); 

在这里,我将打开的接口types连接到打开的类types。

其实在目前的版本应该是非常简单的。 所有你需要做的是提供参数,当你打电话来获得一个新的实例的对象。 要做到这一点,你可以使用objectfactory上的“With”方法。

这允许你使用贪婪的构造函数。 然而,这也意味着你必须知道你需要在这个例子中的集合。 所以这不是注入状态的最佳方法。

 var newObject = ObjectFactory.With<ICollection<CustomerViewModel>>(SomeCollection) .GetInstance<IToCsvService<CustomerViewModel>>();