2013-03-26 78 views
6

我遇到了泛型的奇怪行爲。以下是我用於測試的代碼。通用奇怪的行爲

public static class Program 
{ 
    public static void Main() 
    { 
     Type listClassType = typeof(List<int>).GetGenericTypeDefinition(); 
     Type listInterfaceType = listClassType.GetInterfaces()[0]; 

     Console.WriteLine(listClassType.GetGenericArguments()[0].DeclaringType); 
     Console.WriteLine(listInterfaceType.GetGenericArguments()[0].DeclaringType); 
    } 
} 

輸出:

System.Collections.Generic.List`1[T] 
System.Collections.Generic.List`1[T] 

我就覺得很奇怪的是,第二個Console.WriteLine調用顯示類,而不是一個接口,因爲我用一個泛型類型定義。這是正確的行爲?

我想在我的編譯器中實現泛型類型推斷。假設我有下面的代碼。

public static class GenericClass 
{ 
    public static void GenericMethod<TMethodParam>(IList<TMethodParam> list) { } 
} 

而且我想調用此方法如下:

GenericClass.GenericMethod(new List<int>()); 

爲了檢查推斷的可能性,我得比較傳遞的參數在方法簽名的類型,和類型。但是下面的代碼返回false。

typeof(GenericClass).GetMethods()[0].GetParameters()[0].ParameterType == listInterfaceType; 

我應該總是使用Type.GetGenericTypeDefinition進行這樣的比較嗎?

+0

那麼,在每一種情況下,你是從綁定的泛型列表採購的調用鏈,所以聲明類型將永遠是未綁定的泛型類型。你想做什麼? – JerKimball 2013-03-26 16:49:33

回答

15

你混淆了兩種不同類型,它們都命名爲T.想想看這樣的:

interface IFoo<TIFOO> { } 
class Foo<TFOO> : IFoo<TFOO> {} 

OK,什麼是泛型類型定義的Foo<int>?那是Foo<TFOO>

什麼是接口實施Foo<TFOO>?那是IFoo<TFOO>

什麼是類型參數Foo<TFOO>?顯然TFOO

什麼類型申報TFOOFoo<TFOO>宣佈它。

什麼是類型參數IFoo<TFOO>?顯然TFOO,不是TIFOO

什麼類型申報TFOOFoo<TFOO>宣佈它。 不是IFoo<TFOO>TFOO來自Foo

有意義嗎?

+0

我不遵循從「什麼類型*聲明* TFOO」到爲什麼接口類型打印出爲'System.Collections.Generic.List'1 [T]'的步驟。在MSDN示例中,* interfaces *的名稱是用*具體類型*打印的。我不明白爲什麼誰聲明'TFOO'的問題導致打印出類的名稱而不是接口的名稱。 http://msdn.microsoft.com/en-us/library/system.type.getinterfaces.aspx – 2013-03-26 16:55:55

+0

@EricJ .:鏈接中的示例不使用'.DeclaringType'。 – recursive 2013-03-26 16:57:45

+0

@recursive:我知道,但我仍然不明白這一步。我很確定Eric Lippert在他的評論中是正確的。 – 2013-03-26 17:01:21

2

添加第二個答案,因爲你增加了第二個問題:

我想實現我的編譯器泛型類型推斷......

這樣我假設你正在使用反射來構建編譯器。這可能不是一個好主意。反思比現在早得多,但與直接使用令牌相比,仍然是重量級的。並且反射發射不能發射類型的每種可能的拓撲;它在涉及嵌套結構類型的一些場景中會變得混亂。

我會考慮使用CCI來代替。我們對Roslyn使用了CCI的修改版本。下面

的代碼返回false。

typeof(GenericClass).GetMethods()[0].GetParameters()[0].ParameterType == listInterfaceType 

這是正確的。參數類型是IList<TMethodParam>listInterfaceTypeIList<T>其中TList<T>聲明的通用參數類型,而不是IList<T>聲明的通用參數類型。這些都是不同的類型。

我應該總是使用Type.GetGenericTypeDefinition進行這樣的比較嗎?

如果您想查看兩個泛型類型是否都是相同泛型的結構,那麼是的。如果這不是你想要檢查的,那麼不。

這種類型的系統很複雜,所以要非常小心。

這是使用基於標記的方法而不是基於反射型對象的方法的另一個原因。當你有令牌時,區分TypeDefTypeRef要容易得多。