当前位置:  开发笔记 > 编程语言 > 正文

为什么C#泛型不能像C++模板中那样从泛型类型参数中派生出来?

如何解决《为什么C#泛型不能像C++模板中那样从泛型类型参数中派生出来?》经验,为你挑选了3个好方法。

为什么C#泛型不能像C++模板中那样从泛型类型参数中派生出来?我的意思是我知道这是不可能的,因为CLR不支持这个,但为什么呢?

我知道C++模板和C#泛型之间的深刻差异 - 前者是编译时实体,必须在编译期间解析,而后者是一流的运行时实体.

不过,我没有看到的原因,为什么CLR的设计者并没有拿出一个方案,该方案将最终使CLR泛型类型从泛型类型参数的一个派生.毕竟,这将是非常有用的功能,我个人非常想念它.

编辑:

我想知道一个核心问题,解决这个问题会产生如此高的代价来实现这个功能,这个功能证明它还没有得到实施.例如,检查这个虚构的声明:

class C : T
{
}

正如Eric Lippert已经注意到" 如果T是一个结构怎么办?如果T是一个密封的类型怎么办?如果T是一个接口类型怎么办?如果T是C怎么办?如果T是从C语言中得到什么怎么办?"如果T是带抽象方法的抽象类型?如果T的可访问性低于C怎么办?如果T是System.ValueType怎么办?(你能否有一个继承自System.ValueType的非结构?)System.Delegate怎么样? System.Enum等等? "

正如埃里克继续说的那样," 那些是容易的,显而易见的 ".的确,他是对的.我感兴趣的是一个既不容易也不明显的问题的具体例子,这个问题很难解决.



1> Eric Lippert..:

好吧,首先问问自己可能出现的问题class C : T { }.马上就会想到很多东西:

如果T是结构怎么办?如果T是密封类型怎么办?如果T是接口类型怎么办?如果T是C什么?!如果T是一个派生自的类C怎么办?如果T是带抽象方法的抽象类型怎么办?如果T的可访问性低于C,该怎么办?如果T是System.ValueType怎么办?(你有一个从System.ValueType继承的非结构吗?)System.Delegate,System.Enum等等怎么样?

这些是简单明了的.所提出的特征打开了数百个,如果不是数千个关于类型与其基类型之间的相互作用的更微妙的问题,所有这些都必须仔细指定,实施和测试.毫无疑问,我们会错过一些,从而导致未来发生重大变化,或者通过实现定义的行为来限制运行时.

成本将是巨大的,因此效益最好是巨大的.我没有看到这里的巨大好处.


实现C++模板要困难得多,因为C++模板*在每个构造上重新编译*模板.如果类型参数是引用类型,则C#泛型被编译***并且在运行时为所有构造生成相同的代码.这是一个根本的区别; 这意味着C#泛型必须对任何*可能*构造都是正确的,而C++模板只需要对源代码中有限数量的*actual*构造是正确的.
您是否发现此功能较难实现C++模板?因为它存在于那里,它非常有用并且异常强大.我可以举一个例子,当我发现这个功能非常有用时,因为这与我目前的工作有关.如果你想动态生成一个带有Reflection.Emit的类型,哪个基类型只在运行时知道,那么从它的类型参数派生一个静态编译的泛型非常有用,动态发出的类型可以从中派生出来.
@mark:Eric已成功提供了一份费用清单.你有一系列的好处.成本**非常高**.你要求弄乱类型系统.因此,为了作为一个功能值得,它必须具有非常惊人的好处,一小部分**非常重要的项目(即,**需要**,而不仅仅是一个需要可怕的痛苦和p的大障碍/ invoke),或者对大量项目有惊人的好处.后者绝对不是真的; 大多数程序员都没有意识到(并且会故意不知道)有任何理由这样做,所以好处将是未实现的.
好点子.但泛型类型是开放类型.一个人不能拥有开放泛型类型的任何实例.因此,在实际实例化泛型类型之前,其实际存储器布局可能仍未解析.事实上,即使在今天也是如此.聚合泛型参数类型的实例的泛型类型在实例化之前具有不清楚的内存布局.目前,我不相信不可能提出一系列约束(需要新的约束类型)来使所讨论的继承工作.

2> Eric Lippert..:

好吧,如果你不喜欢我以前的答案,那么让我们采取不同的策略.

你的问题的先决条件是谎言:我们需要一个理由执行一个功能.相反,我们需要一个非常非常好的理由来实现任何功能.它们的前期成本,维护成本和机会成本非常昂贵.(也就是说,您在功能X上花费的时间是您不能花费在功能Y上的时间,这可能会阻止您使用功能Z.)为了负责任地为我们的客户和利益相关者提供价值,我们无法实现每项功能有人碰巧喜欢.

运行时设计师无法证明为什么他们没有实现您觉得特别好的功能.根据成本与用户的利益优先考虑功能,用户并没有完全按照我的要求进行这种继承.这个特殊的功能将大大改变类型系统的分析在运行时的工作方式,对消耗泛型的每种语言都有深远的影响,而且在我看来提供的好处很少.

我们在编译器中使用这种继承 - 用C++编写 - 并且生成的代码很难遵循,难以维护,并且难以调试.我一直在尽力逐步消除这样的代码.我反对在C#中启用相同类型的错误模式,除非这样做有非常令人信服的好处.

以令人信服的方式描述这种巨大利益的任务是针对想要该功能的人,而不是那些必须实现它的人.那么有什么吸引人的好处呢?


当然,我说出问题的方式可能导致人们这么想.原因是我作为一名前C++开发人员,认为从模板参数类型继承的能力是一个非常有用的功能,广泛用于一些重要的库 - ATL和boost等等(我不确定是否STL)可能使用它.尽管C++模板和.NET泛型之间存在根本差异,但我很自然地期望.NET泛型也能拥有它.我很惊讶地发现他们没有.这就是为什么我认为MS想要这个功能,但选择不这样做.
*"我们在编译器中使用这种继承"*...你使用它的事实显示它的用例不是吗?
无论如何,我接受了挑战,并试图收集令人信服的理由,为什么这个功能会很棒.为此,我将启动另一个社区维基问题,并让人们提供原因.我会在发布后立即添加评论链接.

3> maliger..:

代码示例,这可能会有所帮助:

public class SpecialDataRow : T where T : DataRow
{
    public int SpecialFactor { get; set; }
}

这样就可以从DataRow和任何派生的DataRows(如类型化生成的数据集)中创建"特殊"行.

我没有看到任何其他方式如何编写这样的类


这个.这是编写通用派生类的完美有效且理想的方法,并且在许多情况下非常有用.通过强制特定的T:RootClass,你可以消除上面其他帖子中提到的99%的问题.
推荐阅读
贴进你的心聆听你的世界
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有