在C#中为什么我可以打电话
var intStr = 1.ToString();
var strStr = "1".ToString();
1和" 1"是不变的文字所以为什么object.ToString()
不会导致错误?
答案 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);