好问题——就语言设计中的一个有趣问题而言。对于本网站来说,这可能不是一个理想的问题,因为它与具体的实际代码无关。
如果没有明确的typeof 运算符,设计一种可以将类型名称用作表达式的语言是完全可行的。
这样做需要在语言中添加少量额外规则和说明。例如,假设我们有:
enum Color { Red }
class Square
{
Color Color { get; set; }
void M()
{
Type t = Color.GetType();
在今天的 C# 中,这明确意味着为属性 Color 调用 getter 并在结果上调用 GetType。 (有关原因的解释,请参阅规范的“颜色规则”部分。)在您提出的世界中,这可能意味着三件事:
- 为 Color 调用 getter,在结果上调用 GetType,将 Color 的 Type 对象分配给 t。
- Color 生成类型为 Color 的 Type 对象。对该类型调用 GetType,并将 System.Type 的 Type 对象分配给 t。
- Color 指的是 Color 类型,GetType 指的是非静态方法,这是一个错误,因为这是对非静态成员的静态调用。
您需要澄清规范,以便清楚表达式中的颜色何时表示类型,何时表示创建类型对象。因此,提议的功能增加了必须处理的少量歧义,但它是完全可行的。语言设计者可以提出合理的规则。
一种允许通常是编译时分析的一部分的语言元素被解释为创建可以由同一程序中的代码操作的对象的代码的语言称为谐音语言。在 C# 3 之前,C# 是一种非常不和谐的语言;表达式树使 C# 更加谐音。 C# 3 允许将 lambda 视为程序元素,然后用于生成执行 lambda 主体操作的方法,但它还支持从 lambda 到表示 lambda 主体的对象的同形转换。
最谐音的语言之一是 Lisp; Lisp 操作列表,任何 Lisp 程序本身都可以被认为是一个列表。它可以在运行时作为对象而不是代码来引用和操作。因此,我们再次看到了关于语言设计的老笑话的真相:每个语言设计师最终都会重新发明 Lisp,非常糟糕。
我离题了。那么你的问题本质上是:C# 应该是 more 还是 less 就类型名称而言?类型名称是否应该有一个含义——编译时指令——在诸如
之类的上下文中
Foo x = new Foo();
object o = new List<Foo>[] {};
Foo.StaticMethod();
并且有一个非常不同的含义——作为一个可以在运行时在其他上下文中检查的对象的构造:
object t = Foo; // Assign a Type object to t.
?
虽然设计这样的语言肯定是可能,但我不太喜欢它。如果没有一个操作符清楚地指出“嘿,我们正在以同音方式使用通常是编译时元素”,这可能会令人困惑。在 C# 3 之前,没有其他同音语言功能,因此只有一个类型可以用作类型或表达式来生成 Type 对象,这似乎有点奇怪。不幸的是,在某些表达方式中,并不清楚一个特定的简单名称是指“我在编译时使用这种类型”还是“我想创建一个对象”。
使用明确的 typeof 运算符可以缓解所有这些问题;当类型被同义地使用并且对读者来说非常清楚时,它是明确的。
要针对您的问题提出一个非常具体的观点:
当试图分配一个类型到一个属性 System.Type...
一般来说,C# 没有只适用于赋值的特殊规则。 表达式的含义通常是在不考虑使用该表达式的上下文的情况下确定的。当我们说:
x = y;
我们通常不会说“哦,我知道 y 被分配给 x 并且 x 属于 X 类型,所以我将在分析 y 时使用该信息”。相反,分析是从内到外:我们计算出 y 的含义,然后决定它是否与 X 兼容。
这个规则的例外当然是 lambdas; lambdas do 考虑到它们的“目标”类型,因为目标类型可用于推断隐式类型 lambda 的类型。使这些规则正确是非常复杂的。
更一般地说,将赋值表达式设为特殊是一个坏主意。将值分配给变量的方式有很多种:
M(x); // x is assigned to a formal
q = new [] { x }; // x is assigned to the first element of an array
y = new Y() { X = x }; // x is assigned to a property of Y.
您希望所有这些分配的规则保持一致;如果一个表达式的意思是“我是一个类型对象”,那么它应该意味着在该表达式可以出现的每个上下文中,而不仅仅是作为赋值的右侧。