目前框架中只有三个可继承类,其后代可能是值类型:Object
、ValueType
和Enum
。所有这三种类型都是类类型,但任何派生自ValueType
或Enum
将是值类型的类型,以及任何Object
非派生自ValueType
的类型都将是类类型。对于上述以外的任何类型,a class
orstruct
约束要么是多余的,要么是矛盾的;并非巧合的是,C# 不允许直接为上述类型指定约束。
在某些语言和框架中,流行的设计理念是,如果存在一种特定的表达形式,而适用于该通用形式的行为将毫无用处,则语言/框架设计者没有理由不遗余力地禁止这样的形式。在这样Fnord)
的哲学下,将泛型类型限制为密封类型是完全合法的(例如,但是由于将通用约束的正常解释应用于这种情况会产生合理的行为,并且由于可以想象在某些情况下这种约束可能有用(例如,编写代码以使用正在开发且目前已密封的类,但是可能会或可能不会在其最终版本中密封,或者编写代码以与期望特定泛型形式的基于反射的代码接口),哲学将表明将泛型类型约束到密封类应该是合法的。
在其他一些语言和框架中,有一种不同的理念:如果程序员可能期望某种特定形式的构造能够提供超出一般形式的特性,但事实并非如此,并且如果没有这些特性,这种特定形式似乎不会很有用,该语言应该禁止它,即使该结构具有明确定义的精确含义,并且如果该语言的实现者没有看到程序员想要表达该实际含义的理由,则无法通过其他方式表达。
C# 和 .net 在将一个类型参数约束到另一个类型参数方面都没有任何问题,即使该其他参数的类型不会被接受为约束,这表明该限制是由语言人为施加的,原因是上述哲学。不幸的是,恕我直言,因为在很多情况下能够说出来会有所帮助,例如
bool HasAnyFlags<T>(this T enum1, T enum2) where T:struct,System.Enum
即使 .net 可以有效地允许这样的构造,并且即使阻止 C# 排除它的唯一障碍代码显式查找此类约束以禁止它们,C# 设计者还是决定禁止此类构造而不是允许它们表现得像 .net 会解释它们(这意味着它HasAnyFlags
不能直接用 a 做任何T
它不能用 做的事情System.Enum
,并且使用 aT
作为 aSystem.Enum
通常不会比使用 a 快System.Enum
(有时更慢),但T
仍然可以用于几个原因:
- 该方法可以在编译时强制参数必须是*相同*枚举类型
- 该方法可以使用静态类`EnumEvaluator`来生成和缓存`Func`类型的静态委托,这样`HasAnyFlags(T enum1, T enum2)`可以实现为`return EnumEvaluator.HasAnyFlags(enum1,enum2);` . 这样的函数可能比 `Enum.HasFlag` 快十倍以上。
尽管如此,指定此类约束可能很有用,但在 C# 中指定它们的唯一方法是让 C# 源代码指定一些可用作约束的虚拟类型,然后通过实用程序运行编译后的代码,该实用程序将将所有对虚拟类型的引用替换为对首先要使用的类型的引用。