【问题标题】:Why do we have to use typeof, instead of just using the type?为什么我们必须使用 typeof,而不仅仅是使用类型?
【发布时间】:2013-03-20 21:58:39
【问题描述】:

当尝试将类型分配给System.Type 类型的属性时,为什么我们不能这样做?

foo.NetType = bool;

编译器产生这个警告:

“预期的表达式。”

解决方法是这样做:

foo.NetType = typeof(bool);

我的问题是为什么我们不能使用第一种方法?编译器还不够聪明,无法弄清楚我们要在这里完成什么吗?为什么我们必须采用第二种方法 (typeof)?

【问题讨论】:

  • Eric Lippert 是我所知道的唯一 SO 参与者,他可以准确回答这个问题(为什么 C# 语言是这样指定的)。
  • Jon Skeet 也可以,我敢肯定。
  • @EricJ。 - 不,但他对此非常了解。仅仅因为他没有参与创建规范并不意味着他不知道为什么会做出某些决定。
  • @EricJ.:我认为答案很简单;此功能会增加众所周知的运算符的不一致性,而不会带来额外的好处。
  • 但实际上我认为在语法上将这样的功能合并到语言中并没有太大的困难。我无法想到任何模棱两可的用途(如果允许编译器检查赋值的 lhs 是否为 System.Type 类型)但它与其他语法不同,并且不会我觉得不太合适。

标签: c#


【解决方案1】:

好问题——就语言设计中的一个有趣问题而言。对于本网站来说,这可能不是一个理想的问题,因为它与具体的实际代码无关。

如果没有明确的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.

您希望所有这些分配的规则保持一致;如果一个表达式的意思是“我是一个类型对象”,那么它应该意味着在该表达式可以出现的每个上下文中,而不仅仅是作为赋值的右侧。

【讨论】:

    【解决方案2】:

    抱歉,我一开始误解了你的目标。但是,您仍然有些困惑。

    您正在尝试将Type 对象的实例 分配给属性。 bool 不是 Type 类的实例,它是它自己的类型。我很欣赏这个术语有点令人困惑,但它们是两个不同的东西。这就是它不起作用的原因。

    【讨论】:

    • 为什么要这样解决它:foo.NetType == typeof(bool); 我正在尝试为属性分配类型,== 是为了相等,而不是分配。 foo.NetType = typeof(bool); 在我的代码中工作得很好,所以我不明白这有什么问题。
    • @BobHorn:对不起,我的错误。但是,您仍然感到困惑。您正在尝试将 Type 对象的 instance 分配给属性。 bool 不是 Type 类的实例。它们是两种不同的东西。
    • 我明白为什么它不起作用了。人们一直认为我不明白。我愿意。我在问为什么不能对其进行更改以使其正常工作。
    • @BobHorn:我回答了你。这没有意义,这就是原因。它们是两种不同的东西。当然编译器团队可以为这个场景做一个特例并实现它,这不是技术上的不可能。但他们为什么要这样做?它无缘无故地增加了复杂性,只是两次为您节省了几次击键,更重要的是,它根本没有意义,除非您知道它是等式运算符的一种特殊情况。在此处阅读 Eric Lippert 的答案:stackoverflow.com/questions/2806894/…
    • 我明白你在说什么,我刚刚给你 +1 小费。 typeof 返回一个类型的实例,这就是属性所持有的。
    【解决方案3】:

    所以这是一个 SWAG:

    如果我有课:

    public class Foo
    {
        public static int Bar = 1;
    }
    

    我有一些类似的代码:

    var foo = Foo;
    

    你可能会说“好吧,那肯定是类型”

    现在如果我有类似的东西:

    public class Bar
    {
        public void Foo ()
        {
              var hmm = Foo;
        }
    }
    

    我是什么意思?类型 Foo?方法 Foo?命名空间(如果存在)Foo?

    通过将它包装在 typeof 中,我们可以明确表达我们想要什么。此外,它会生成特定的 IL,但我假设您的问题隐含的意思是“为什么编译器不更聪明?”

    【讨论】:

    • 额外的随机想法:拉类型并不总是微不足道的操作;使其成为显式操作使意图清晰,还可以防止依赖类型加载等带来的意外副作用。
    • +1。我喜欢“明确”的参考。但是,如果我们不使用 var,我看不出Foo foo = Foo 可以采取其他方式。
    • @BobHorn 我明白你的意思;我的意思是,简短的答案是 EdS 的“它们只是不同的东西”,但试图从编译器开发人员的头脑中得出。
    猜你喜欢
    • 2020-08-10
    • 2021-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-04
    • 2017-01-09
    相关资源
    最近更新 更多