为什么我们必须使用typeof而不是仅仅使用类型?

时间:2013-03-20 21:58:39

标签: c#

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

foo.NetType = bool;

编译器会产生此警告:

  

“表达预期。”

解决问题的方法是这样做:

foo.NetType = typeof(bool);

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

3 个答案:

答案 0 :(得分:21)

好问题 - 只要它是语言设计中的一个有趣问题。这可能不是本网站的理想问题,因为它不是特定的实际代码。

设计一种语言是完全可行的,在该语言中,类型名称可以用作没有明确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指的是非静态方法,这是一个错误,因为这是对非静态成员的静态调用。

您希望澄清规范,以便在表达式中的Color表示类型以及何时表示创建类型对象时很清楚。因此,所提出的特征增加了必须处理的少量歧义,但它完全可行。语言设计者可以提出合理的规则。

一种语言,它允许通常是编译时分析一部分的语言元素被解释为创建可以由同一程序中的代码操作的对象的代码 同性语言。 C#在C#3之前是一种非常非同音异义的语言;表达树使C#更加同质化。 C#3允许lambdas被视为程序元素,然后用于生成执行lambda体动作的方法,但它也支持从lambda到表示lambda体的对象的homoiconic转换。

一种最同质的语言是Lisp; Lisp操纵列表,任何Lisp程序本身都可以作为列表;它可以在运行时作为对象而不是代码进行引用和操作。所以我们再一次在这里看到关于语言设计的老笑话的真相:每个语言设计师最终都重新发明了Lisp,非常糟糕。

我离题了。那么你的问题基本上是:C#在类型名称方面是更多还是更少 homoiconic?类型名称是否具有一个含义 - 编译时指令 - 在

等上下文中
Foo x = new Foo();
object o = new List<Foo>[] {};
Foo.StaticMethod();

并且具有非常不同的含义 - 作为可在运行时在其他上下文中检查的对象的构造:

object t = Foo; // Assign a Type object to t.

虽然设计这样的语言肯定是可能,但我并不喜欢它。没有操作员在那里清楚地呼唤&#34;嘿,我们正在以同性化的方式使用通常是编译时的元素&#34;,它可能令人困惑。在C#3之前,没有其他同源语言特性,所以只有一个类型可以用作导致Type对象的类型或表达式似乎有点奇怪。并且看起来非常不幸的是,在一些表达中,不清楚一个特定的简单名称是否意味着&#34;我在编译时使用这种类型&#34;或者&#34;我想制作一个对象&#34;。

拥有明确的typeof运算符可以缓解所有这些问题;当同类型地使用该类型并且读者非常清楚时,这是明确的。

要解决有关您问题的非常具体的一点:

  

尝试分配类型类型为System.Type的属性

一般来说,C#没有特殊规则只适用于作业。 通常在不吸引使用表达式的上下文的情况下确定表达式的含义。当我们说:

x = y;

我们通常不会说&#34;哦,我知道y被分配给x而x是X类型所以我将在y&#34的分析中使用该信息;。相反,分析从内到外:我们找出y的含义,然后决定它是否与X兼容。

这条规则的例外当然是lambdas; lambdas 考虑到他们的&#34;目标&#34; type,因为目标类型可用于推断隐式类型的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.

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

答案 1 :(得分:6)

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

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

答案 2 :(得分:2)

所以这是一个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,但我假设您的问题隐含地意味着“为什么编译器不是更聪明?”