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

本文关键字:对象 扩展 方法 调用 我可以 常量 为什么 | 更新日期: 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);