2012-07-10 61 views
1

我有以下類別:StructureMap開放式泛型類型

public interface IRenderer<T> 
{ 
    string Render(T obj); 
} 

public class Generic<T> { } 

public class SampleGenericRenderer<T> : IRenderer<Generic<T>> 
{ 
    public string Render(Generic<T> obj) 
    { 
     throw new NotImplementedException(); 
    } 
} 

我想能夠調用StructureMap與 ObjectFactory.GetInstance<IRenderer<Generic<string>>>();和接收SampleGenericRenderer<string>

我正在使用以下注冊並在調用GetInstance時收到此錯誤。 「無法轉換類型的對象:

ConsoleApplication1.SampleGenericRenderer'1 [ConsoleApplication1.Generic'1 [System.String]] ' 鍵入 ' ConsoleApplication1.IRenderer'1 [ConsoleApplication1.Generic'1 [系統。.String]

public class CoreRegistry : Registry 
{ 
    public CoreRegistry() 
    { 
     Scan(assemblyScanner => 
     { 
      assemblyScanner 
       .AssemblyContainingType(typeof(IRenderer<>)); 
      assemblyScanner.AddAllTypesOf(typeof(IRenderer<>)); 
      assemblyScanner 
       .ConnectImplementationsToTypesClosing(
        typeof(IRenderer<>)); 
     }); 
    } 
} 

有什麼辦法來配置StructureMap,使其產生的SampleGenericRenderer<string>代替SampleGenericRenderer<Generic<string>>

更新:我結束了我自己爲這個依賴關係的子集進行類型構造。因爲它們將上下文綁定與大量不受支持的通用綁定結合在一起,所以這變成了最乾淨的解決方案。

回答

1

我不相信StructureMap具有用於封閉的任何機制內部這樣的通用參數。

這是不理想的,但你可以嘗試創建自己的IRegistrationConvention,每當遇到一個類型,它是一個封閉式的Generic<>,做到以下幾點:

var generic_t = typeof(Generic<>).MakeGenericType(type); 
var sample_renderer_t = typeof(SampleGenericRenderer<>).MakeGenericType(type); 
var renderer_t = typeof(IRenderer<>).MakeGenericType(generic_t); 
graph.AddType(renderer_t, sample_renderer_t); 

詳情請參閱http://docs.structuremap.net/ScanningAssemblies.htm#section11

+0

這絕對是我走下坡路,我認爲它會奏效。有相當多的掃描涉及使它在實際的代碼庫中工作,因爲我必須找到所有可能的通用參數,並且在編譯時我不知道渲染器或渲染類型的任何內容,但最終會讓其他的代碼更清潔。值得注意的是,ITypeScanner在最近版本的StructureMap中被IRegistrationConvention所取代。文檔有點過時了! – 2012-07-11 13:58:51

+0

@ShaneFulmer我忘了那個重命名。事實上,我會相應地更新答案。 – Pete 2012-07-11 14:27:16

1

對於我這樣工作的:

class Program 
{ 
    static void Main() 
    { 
     ObjectFactory.Configure(x=>x.AddRegistry<CoreRegistry>()); 

     var instance = ObjectFactory.GetInstance(typeof(IRenderer<string>)) as IRenderer<Generic<string>>; 

     var render = instance.Render(new Generic<string>()); 

    } 
} 

這將引發異常:

ObjectFactory.GetInstance<IRenderer<Generic<string>>>(); 

什麼是你真正的問題?

編輯:

在某些情況下這可能是工作太(如果你沒有在設計時知道Generic<string>):

static void Main() 
{ 
    ObjectFactory.Configure(x => x.AddRegistry<CoreRegistry>()); 

    var instance = ObjectFactory.GetInstance(typeof(IRenderer<string>)); 
    var methodInfo = instance.GetType().GetMethod("Render"); 
    methodInfo.Invoke(instance, new[] { new Generic<string>() }); 
} 
+0

嗯,我想這個例子的問題是,我不知道任何關於SampleGenericRenderer從客戶端代碼,所以我不能施展它。我從客戶那裏得知的是,我有一個通用的,我需要一個能夠處理其渲染的類。 – 2012-07-10 20:24:49

+0

我改變了代碼。是泛型<> DTO? – Rookian 2012-07-10 20:54:55

+0

不,我不會認爲它是一個真正的例子中的DTO。我認爲如果我沒有遺漏某些東西,那麼更改後的代碼會返回錯誤的渲染器。在實際的代碼中,除了IRenderer >之外,還會有一個IRenderer 。 – 2012-07-11 13:52:02

2

正如皮特所解釋的,StructureMap可能無法做到這一點。其他的DI容器可能會產生更多的成功,但並非所有的容器都對更復雜的通用欺騙有很大的支持。我唯一知道的就是Simple Injector。用簡單的噴油器,你只需要以下配置:關於這個方法

var container = new Container(); 

container.Register(typeof(IRenderer<>), typeof(SampleGenericRenderer<>)); 

// Usage 
var renderer = container.GetInstance<IRenderer<Generic<string>>>(); 

renderer.Render(new Generic<string>()); 

更多信息,可以發現here

+1

隨着泛型的複雜性,我試圖使用這種模式,我想我需要一些簡單注入器添加的額外擴展點。我遇到了很多與StructureMap有關的限制,所以我打算給Simple Injector一個嘗試! – 2012-07-15 05:15:31