为什么在generics参数约束中强制执行某些排序?
在定义generics类型参数的约束时,我们必须将class()
放在前面,将new()
放在末尾。
为什么这样,为什么我不能按任何顺序放置约束?
除了class
/ struct
之外,还有其他任何限制,最后是new()
吗?
例:
protected T Clone() where T : class, ICopyable, new()
选择该订单没有特别的理由。 所选择的顺序从更一般到更具体,我认为这是一个相当不错的属性。
至于“为什么需要订单?”这个问题,实施和测试团队可以更容易地通过语言强加清晰,明确的命令。 我们可以允许约束以任何顺序出现,但这会给我们带来什么?
我在语言上工作的时间越长,我就越觉得每次给用户一个选择,你就给他们一个做出错误选择的机会。 C#的一个基本设计原则是我们告诉你什么时候出错了并强迫你做对了 – 这不是JavaScript的基本设计原则。 它的基本设计原则是“混淆并尝试做用户的意思”。 通过对C#中正确语法的更多限制,我们可以更好地确保在程序中很好地表达预期的语义 。
例如,如果我今天正在设计一种类似C#的语言,那么我就无法使用如下模糊语法:
class C : X , Y
要么
... where T : X, Y
Y显然是一个界面。 是X? 我们无法从语法上分辨出X是打算成为接口还是类。 可以说这种模糊性使得检测基类型与接口的周期等问题变得非常复杂。 对于所有相关的人来说,如果它更加冗长,就像在VB中那样更容易。
像大多数语法相关的问题一样,基本答案是因为规范说明了这一点。 我们从C#5.0规范中获得了generics类型约束的以下语法(第10.1.5节)
型参数的约束:
primary-constraint secondary-constraints constructor-constraint primary-constraint , secondary-constraints primary-constraint , constructor-constraint secondary-constraints , constructor-constraint primary-constraint , secondary-constraints , constructor-constraint
主要约束:
class-type class struct
二次约束:
interface-type type-parameter secondary-constraints , interface-type secondary-constraints , type-parameter
构造函数约束:
new ( )
Eric Lippert在解释为什么以这种方式设计方面做得非常出色,所以我不会对此进行阐述。