In C# why I can call
var intStr = 1.ToString();
var strStr = "1".ToString();
1 and "1" are constant literals so why object.ToString()
is not causing errors?
In C# why I can call
var intStr = 1.ToString();
var strStr = "1".ToString();
1 and "1" are constant literals so why object.ToString()
is not causing errors?
Why I can call object extension methods on constants?
Those aren't extension methods.
1
and"1"
are constants so whyToString()
is not causing errors?
Your question asks "why not" without ever explaining why you think this should be a problem in the first place. When asking questions of this form in the future please say why you think the operation ought to be disallowed.
So let's try to read your mind. Here's a question you could have asked:
1
and"1"
are literals but the left hand side of a dot must be a symbol, likex
, so why is1.ToString()
not causing errors?
The supposition is incorrect. The thing on the left hand side of a member access dot must be an expression. There are restrictions on that expression; for example, it cannot be a void-returning method call. But there is no restriction on it being a literal.
Here's another question you could have asked:
1
is a constant of value type but the receiver of a method of a value type must be a variable, because thethis
in the method is aref
to a variable. So why is1.ToString()
not causing errors?
If the receiver of a method call is of a value type and the this
has to be of ref
type but the receiver expression is not classified as a variable then the compiler copies the value to a temporary variable and passes a ref
to that variable.
This means that if the method mutates the variable, the mutation is lost because it is performed on a copy. This is yet another reason why mutable value types are a bad practice. It is easy to lose a mutation accidentally!
Here's another question you could have asked:
1.
is the beginning of a float, double or decimal literal; the thing that comes next should be a digit. So why is1.ToString()
not causing errors?
The question makes an incorrect supposition. The lexer checks whether the thing that follows the dot is a digit; if it is then it keeps lexing the literal as a float, double or decimal. (Which it is will be determined by the suffix, if any.) If the thing that follows the dot is not a digit then the lexer lexes the dot as a member access dot and starts lexing a new token for the ToString
.
They are initialised from constant literals (in the program text), but they are actually objects (in that they are logically treated as objects), and all objects implement ToString()
So 1
is of type System.Int32
.
Therefore you can call ToString()
for them.
The IL generated for this is something like this:
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()
Note that the ldc.i4.1
is a special instruction that pushes a System.Int32
with value 1 onto the stack. That, specifically, is the instruction that actually "creates" the the System.Int32
value object.
Also note that although System.Int32 is a value type, it is also treated as an object, so that the following statement is always true:
bool isObject = (1 is object);