2016-04-01 71 views
11

爲什麼我不能撥打SomeGenericMethod<SomeGenericType<>>如何將泛型傳遞給泛型方法?

class NotGeneric { } 

class Generic<T> { } 

class Program 
{ 
    static void Main(string[] args) 
    { 
     PrintType(typeof(NotGeneric)); 
     PrintType(typeof(Generic<>)); 
     PrintType<NotGeneric>(); 
     PrintType<Generic<>>(); // compiler goes crazy here 
    } 

    static void PrintType<T>() 
    { 
     Console.WriteLine(typeof(T)); 
    } 

    static void PrintType(Type t) 
    { 
     Console.WriteLine(t); 
    } 
} 
+0

基本上'typeof'可以採用通用類名稱,它沒有定義通用類型,但是如果將類型作爲通用類型傳遞,它必須是一個完全定義的類型,而'Generic <>'不是。 – juharr

+1

@juharr像往常一樣在這裏,迄今爲止最好的答案是在評論中。所以可以肯定地說,這是不可能的**。 – talles

+0

我認爲rbaghbanli在說同樣的事情。但是,不能將'Generic <>'作爲泛型類型傳遞。注意如果你使用'typeof(Generic )',你得到的Type與typeof(Generic <>)類似,但GenericTypeArguments不會是一個空數組,而GenericTypeParameters將會是空數組。 'typeof'只是給你一個描述你傳遞給它的類型的對象。 – juharr

回答

2

我爲什麼不能叫SomeGenericMethod<SomeGenericType<>>

最簡單的回答是:因爲language specification是這麼說的:

4.4構造類型

泛型類型聲明,本身就表示一種未綁定的泛型,它被用作「藍圖」來形成許多不同的類型應用類型參數。類型參數寫在通用類型名稱後面的尖括號(<和>)中。包含至少一個類型參數的類型稱爲構造類型。構造類型可用於大多數語言中可以顯示類型名稱的地方。 未綁定的泛型類型只能在typeof-表達式(§7.6.11)中使用。

4.4.3結合和未結合類型

術語未綁定類型是指一種非通用型或未結合的通用類型。術語綁定類型是指非泛型類型或構造類型。 未綁定類型是指由類型聲明聲明的實體。未綁定的泛型類型本身不是一個類型,不能用作變量的類型,參數或返回值,或者作爲基類型。 唯一可以引用非綁定泛型類型的構造是typeof表達式(第7.6.11節)。

爲什麼C#規範是這麼說的?因爲CLI spec決定了還有:

II.9.4實例化泛型類型

...

CLI不支持泛型類型的實例部分。泛型類型不得在元數據簽名blob中的任何地方顯示爲無實例。

好的,現在讓我們停止使用法律術語。實際的回答你的問題是:

當你調用SomeMethod<SomeType>()首次,CLR會調用JIT編譯器,它會讀取SomeMethod<T>,替代T,並且創建代表SomeMethod<SomeType>新的可執行代碼。

當您撥打SomeMethod<SomeOtherType>()時,需要重複該過程,將爲SomeMethod<SomeOtherType>生成全新的代碼。

您不能只爲非結合泛型類型(如Generic<>)創建有效代碼。在一般情況下,JIT無法知道在不知道T的情況下生成什麼代碼表示。

  • 如果Tstring和您的方法聲明T類型的局部變量,所述JIT將分配堆棧空間或使用寄存器與天然指針的大小。
  • 如果TGuid,JIT將不得不爲固定的128位值分配堆棧空間。如果它不知道T將會是什麼,它就不能生成代碼。

因此,一般,您無法生成未綁定類型的可執行代碼。爲什麼你可以說可能對你提供的代碼段做了這樣的事情,這將需要特殊的外殼,並且如果你在PrintType方法中添加了T本地代碼,你的調用代碼將停止工作。由於泛型必須在組件之間可重用,因此調用代碼不能假定被調用方法的任何內容。

+0

現在,這是一個答案!所以最後是因爲JIT編譯器不知道在方法調用中爲Generic <>產生了什麼(這是JIT編譯「錯誤」)。 – talles

-2

嘗試這樣的事:

public class Generic<T> 
{ 
    public void PrintType(T param) 
    { 
     Console.WriteLine(param.GetType().Name); 
    } 
} 
+2

這是怎麼回答爲什麼PrintType(typeof(Generic <>))''printType >();'doesnt'? – juharr

+0

你顯然不能使用'Generic <>',你需要指定類型,即'Generic ' –

+1

對,但是OP確實在問爲什麼'typeof(Generic <>)'確實有效。 – juharr

0
PrintType<Generic<YOU NEED TO PUT TYPE HERE>>(); 
+3

你應該看看這個問題,爲什麼可以做'typeof(Generic <>)'。 – juharr

+0

@juharr對不起,他有很多問題。 – skalinkin

7

編譯器需要特殊類型的專門泛型方法和Generic<>不專業,它是通用的。所以,雖然Generic<>是一種類型,但它並不專門用於泛型方法的專業化。

+0

'typeof(Generic <>)'中的'Generic <>'在編譯時解決,不是嗎? – talles

+3

正如我寫的,'泛型<>'是一個類型,所以'typeof(泛型<>)'沒有問題。它是通用類型。但是泛型不能用於專業化,因爲它們並不是專門化的。 –

相關問題