2009-10-19 30 views
3

我試圖給我們的Io​​C容器添加通用服務支持,並且我有一個問題。C#中通用類型構造函數的解析,IoC中使用通用服務註冊

比方說,我有以下類型:

public interface IService<T> { ... } 
public class Service<T> : IService<T> { ... } 

,然後將下面的代碼:

Type type = typeof(Service<>); // <-- notice no specific type here 
ConstructorInfo ctor = LogicToFindCtor(type); // <-- picks one of the ctors 

現在,在這一點,我有一個通用的類型,我不能調用構造函數,因爲它是通過具有泛型參數的泛型類型獲得的。

所以,因爲在我的代碼我試圖解決一個特定的類型,說IService<Employee>,我可以很容易地通過我的代碼,我需要使用的具體類型Service<T>解決這一發現,那我需要注入輸入Employee代替T

但是,我的問題是這樣的:鑑於我有我想調用的ctor已經制定了通用的非特定類型,我如何找到特定類型的正確構造函數。

Type specificType = typeof(Service<Employee>); 
ConstructorInfo specificCtor = MapGenericToSpecific(ctor, specificType); 

編輯:我注意到,財產MetaDataToken兩個構造函數(一個從非特定類型和特定類型的)具有相同的價值在這裏,我可以用它來搭配?它仍然需要一個循環來找到正確的構造函數,但是用一個簡單的if語句找到正確的構造函數的循環遠比看看參數並嘗試匹配這種方式更合適。我已經更改了下面的代碼。這現在編譯和運行,是否有更好的方法,甚至更少的反射,也許直接查找構造函數表中找到基於metadatatoken值的構造函數?

下面的代碼:

using System; 
using System.Linq; 
using System.Reflection; 
using System.Diagnostics; 
namespace ConsoleApplication10 
{ 
    public class ActivationAttribute : Attribute { } 

    public class TestClass<T1, T2> 
    { 
     public TestClass(String p1) 
     { 
      Console.Out.WriteLine("Wrong constructor"); 
     } 

     [Activation] 
     public TestClass(T1 p1) 
     { 
      Console.Out.WriteLine("Right constructor, p1=" + p1); 
     } 

     public TestClass(T2 p2) 
     { 
      Console.Out.WriteLine("Wrong constructor"); 
     } 

     public TestClass() 
     { 
      Console.Out.WriteLine("Wrong constructor"); 
     } 

     public TestClass(T1 p1, T2 p2) 
     { 
      Console.Out.WriteLine("Wrong constructor"); 
     } 

     public TestClass(String p1, T2 p2) 
     { 
      Console.Out.WriteLine("Wrong constructor"); 
     } 

     public TestClass(String p1, Int32 p2) 
     { 
      Console.Out.WriteLine("Wrong constructor"); 
     } 
    } 

    public class Program 
    { 
     static void Main(string[] args) 
     { 
      // This is the type I have in my IoC container 
      Type genericType = typeof(TestClass<,>); 

      // This is the constructor I locate 
      ConstructorInfo genericCtor = 
       (from ctor in genericType.GetConstructors() 
       where ctor.IsDefined(typeof(ActivationAttribute), false) 
       select ctor).First(); 
      Debug.Assert(genericCtor != null); 

      // RESOLUTION STEP 

      // Upon resolution, two actual types are specified 
      Type[] genericArguments = new Type[] { typeof(String), typeof(Int32) }; 

      // So I create the actual type from the generic one 
      Type specificType = genericType.MakeGenericType(genericArguments); 

      // Can I look up the "genericCtor.MetadataToken" property directly? 
      // or is this as good as it gets? 
      ConstructorInfo specificCtor = 
       (from ctor in specificType.GetConstructors() 
       where ctor.MetadataToken == genericCtor.MetadataToken 
       select ctor).First(); 
      Debug.Assert(specificCtor != null); 

      Debug.Assert(specificCtor != null, "No matching constructors was found"); 
      Object instance = specificCtor.Invoke(new Object[] { "Test" }); 

      Console.Out.Write("Press enter to exit..."); 
      Console.In.ReadLine(); 
     } 
    } 
} 

回答

2

可以依靠MetadataToken保持不變的有界和無界構造。元數據是用IL代碼創建的,它是類型的一部分,與通用參數綁定無關。

.NET不會爲每個泛型參數的使用創建不同的類型(例如List<int>List<bool>)。它是相同的類型,但在每次調用時,有限的泛型參數都通過方法參數傳遞給堆棧(我知道您可能已經知道所有這些,但我只是確認)。

因此,MetadataToken當類泛型參數綁定到特定類型時,附加到該類型在運行時不會更改。例如:

bool unboundAndBoundHasSameMetadataToken = 
      typeof(IList<>).MetadataToken == typeof(IList<int>).MetadataToken; 

bool boundedClassesHasSameMetadataToken = 
      typeof(IList<bool>).MetadataToken == typeof(IList<int>).MetadataToken; 

Assert.IsTrue(unboundAndBoundHasSameMetadataToken); 
Assert.IsTrue(boundedClassesHasSameMetadataToken); 

底線,MetadataToken是IL「的一部分」和相同類型具有不同的通用參數結合的實例沒有什麼不同。


出於好奇,(我可能失去了一些東西),爲什麼不使用發現有界類型激活構造它的綁定類型中找到的相同,是過濾?激活屬性也修飾了有界的構造函數。

+0

請原諒我的無知,但是當你說「有界和無界的構造函數」時,實際上有什麼區別? (我知道我可能沒有使用正確的術語,而你的可能是正確的)你的意思是,我發現我的泛型類型的構造函數,當我還不知道T的實際類型(無界),與我需要爲特定類型定位的構造函數相比,當我知道T的類型時?再次,請原諒我缺乏使用正確的術語,因爲我不知道如何準確地描述我的意思。 – 2009-10-30 23:19:03

+0

...和[Activation]屬性上的良好通話....(打頭像)不知道爲什麼我沒有想到... – 2009-10-30 23:20:08

+0

但是,只是爲了得到這個直線,你是說如果我檢查'SomeGenericType(T)'類型,我仍然不知道T的類型,與'SomeGenericType(T)'的* specific *類型相比,方法將具有相同的MetadataToken值? (例如,值不取決於T的類型?) – 2009-10-30 23:22:19

相關問題