C#为什么我可以在常量上调用对象扩展方法?

时间:2014-03-13 13:52:57

标签: c# .net

在C#中为什么我可以打电话

var intStr = 1.ToString();
var strStr = "1".ToString();

1和" 1"是不变的文字所以为什么object.ToString()不会导致错误?

2 个答案:

答案 0 :(得分:7)

  

为什么我可以在常量上调用对象扩展方法?

那些不是扩展方法。

  

1"1"是常量,为什么ToString()不会导致错误?

你的问题要求"为什么不" 没有解释为什么你认为这应该是一个问题。在将来询问此表格的问题时,请说明为什么您认为该行动应该被禁止。

所以,让我们试着读懂你的想法。这是您可以提出的问题:

  

1"1"文字,但点的左侧必须是符号,例如x,那么为什么1.ToString()不会导致错误?

假设不正确。成员访问点左侧的东西必须是表达式。这种表达有限制;例如,它不能是返回void的方法调用。但是对它来说没有任何限制。

这是您可以提出的另一个问题:

  

1是值类型的常量,但值类型的方法的接收者必须是变量,因为方法中的this是{{ 1}}变量。那么为什么ref不会导致错误?

如果方法调用的接收者是值类型且1.ToString()必须是this类型但接收器表达式未被归类为变量,则编译器将值复制到a临时变量并将ref传递给该变量。

这意味着如果方法变异变量,则变异会丢失,因为它是在副本上执行的。这是可变值类型是一种不好的做法的另一个原因。很容易意外丢失突变!

这是您可以提出的另一个问题:

  

ref是float,double或decimal字面的开头;接下来的事情应该是一个数字。那么为什么1.不会导致错误?

这个问题做出了错误的假设。词法分析器检查点后面的东西是否是数字;如果它然后它保持lexing文字作为浮点数,双精度或小数。 (它将由后缀决定,如果有的话。)如果点后面的东西不是数字,则词法分析器将点作为成员访问点,并开始为1.ToString()添加新的令牌

答案 1 :(得分:5)

它们是从常量文字(在程序文本中)初始化的,但它们实际上是对象(因为它们在逻辑上被视为对象),并且所有对象都实现了ToString()

因此1的类型为System.Int32

因此,您可以为他们致电ToString()

为此生成的IL是这样的:

L_0001: ldc.i4.1 
L_0002: stloc.1 
L_0003: ldloca.s CS$0$0000
L_0005: call instance string [mscorlib]System.Int32::ToString()

请注意,ldc.i4.1是一个特殊指令,它将值{1}的System.Int32压入堆栈。具体而言,这是实际"创建" System.Int32值对象。

另请注意,尽管System.Int32是值类型,但它也被视为对象,因此以下语句始终为true:

bool isObject = (1 is object);