为什么我可以在常量上调用对象扩展方法
本文关键字:对象 扩展 方法 调用 我可以 常量 为什么 | 更新日期: 2023-09-27 17:49:56
为什么我可以在c#中调用
var intStr = 1.ToString();
var strStr = "1".ToString();
1和"1"是常量,所以为什么object.ToString()
不会引起错误?
为什么我可以在常量上调用对象扩展方法?
这些不是扩展方法。
1
和"1"
是常数,所以为什么ToString()
不引起错误?
你的问题问了"为什么不",而没有解释为什么你认为这应该是一个问题。以后问这种形式的问题时,请说明为什么你认为该操作应该被禁止。
让我们试着读懂你的心。这是一个你可以问的问题:
1
和"1"
是文字,但点的左侧必须是符号,如x
,那么为什么1.ToString()
不会引起错误?
假设是不正确的。成员访问点左边的东西必须是表达式。这种表达是有限制的;例如,它不能是一个空返回方法调用。但是没有限制它是一个文字。
还有一个你可以问的问题:
1
是值类型的常量,但是值类型方法的接收者必须是变量,因为方法中的this
是变量的ref
。那么为什么1.ToString()
不会导致错误呢?
如果方法调用的接收者是值类型,并且this
必须是ref
类型,但是接收者表达式没有被分类为变量,那么编译器将该值复制到一个临时变量中,并将ref
传递给该变量。
这意味着如果方法改变了变量,那么这个改变将丢失,因为它是在一个副本上执行的。这也是为什么可变值类型是一种不好的做法的另一个原因。不小心失去一个突变是很容易的!
还有一个你可以问的问题:
1.
是浮点、双精度或十进制字面值的开头;接下来的数应该是一个数字。那么为什么1.ToString()
不会导致错误呢?
这个问题做了一个错误的假设。词法分析器检查点后面的东西是否为数字;如果是,则继续将字面值作为浮点数、双精度或小数进行lexing。(如果有的话,它将由后缀决定。)如果点后面的东西不是数字,词法分析器将点作为成员访问点词法,并开始词法ToString
的新令牌。
它们是由常量字量初始化的(在程序文本中),但它们实际上是对象(因为它们在逻辑上被视为对象),并且所有对象都实现了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是值类型,它也被视为对象,因此以下语句始终为真:
bool isObject = (1 is object);