[英]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.