[英]Polymorphism, overloads and generics in C#
class Poly
{
public static void WriteVal(int i) { System.Console.Write("{0}\n", i); }
public static void WriteVal(string s) { System.Console.Write("{0}\n", s); }
}
class GenWriter<T>
{
public static void Write(T x) { Poly.WriteVal(x); }
}
為什么無辜(對於C ++程序員)方法寫入在C#中是不可接受的?
您可以看到編譯器在實例化之前嘗試將參數類型T與具體重載匹配:
當然。 目的不是使用上面的靜態方法,目的是創建一個具有多態行為的包裝器。 注意:我使用的是VS 2010。
請注意,所有需要的信息都可在編譯時獲得。 再一次:問題是在模板實例化之前執行驗證。
討論后增加:
好吧,可能我沒有正確地強調這一點。 問題不僅在於泛型和模板之間的區別,還在於解決以下問題:給定一組解決不同類型的重載,我想生成一組包裝類,為這些類型提供虛方法(多態)。 運行時虛擬方法的解析價格很小,並沒有達到性能。 這是C ++模板很方便的地方。 顯然, 動態的運行時類型解析的開銷是完全不同的。 因此,問題是,是否可以在不復制代碼的情況下將現有的重載轉換為多態,並且不會犧牲性能損失(例如,我不確定動態與“switch”相比,除了更好的語法之外的“switch”)。
到目前為止我見過的解決方案之一是生成/發出代碼(sic!),即不是自動剪切和粘貼。
因此,我們只需手動執行或僅重新創建宏/模板處理器,而不是C ++模板處理。
還有什么更好的?
簡短回答:
C#泛型不是C ++模板; 盡管它們的語法相似但卻完全不同。 模板是在編譯時構建的,每次實例化一次,並且模板化代碼必須僅對實際提供的模板參數是正確的。 模板在每次實例化時執行重載解析和類型分析等任務; 它們基本上是源代碼文本上的智能“搜索和替換”機制。
C#泛型是真正的通用類型; 它們必須對任何可能的類型參數都是正確的。 分析通用代碼一次 ,重載分辨率完成一次 ,依此類推。
答案很長:這是重復的
請查看詳細的長答案。
另見我關於這個主題的文章:
http://blogs.msdn.com/b/ericlippert/archive/2009/07/30/generics-are-not-templates.aspx
為什么你不能簡單地寫:
public static void Write<T>(T x) { System.Console.Write("{0}\n", x); }
C ++和C#泛型不同( http://msdn.microsoft.com/en-us/library/c6cyy67b(v=VS.80).aspx ,在您最喜歡的搜索網站上搜索“c#c ++泛型差異”)
簡短:C#編譯器必須通過查看類本身來創建具有所有類型匹配的完整GenWriter<T>
類。 所以它不知道T是否只是int / string或任何其他類型。
C ++編譯器通過查看通用GenWriter<int>
和聲明GenWriter<T>
實例化來創建實際類,然后為該特定實例創建類。
如果有人要調用GenWriter(5.0)
,這將被推斷為GenWriter<double>(5.0)
,並且Write(T x)
內的方法調用將變為:
public static void Write(double x) { Poly.WriteVal(x); }
WriteVal
沒有超載,需要加倍。 編譯器通知您沒有WriteVal
有效重載。
C#泛型和C ++模板並不完全等效。
你不能在C#中這樣做,因為編譯器不知道編譯時x的類型是什么。
如果不了解T的實際類型,編譯器會擔心您可能打算執行自定義轉換。 最簡單的解決方案是使用as運算符,因為它無法執行自定義轉換,因此無法實現。
更普遍的解決方案是首先投射到對象。 這是有幫助的,因為拳擊拆箱問題:
return (int)(object) x;
請記住,C#Generics不像C ++模板。 C ++模板是分別為每種類型編譯的代碼片段。 雖然C#泛型是以匯編方式編譯的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.