How this occurs is an implicit cast ("A char can be implicitly converted to ushort, int, uint, long, ulong, float, double, or decimal." (charMSDN).
The most simple form of the reproduction can be found as
int slash = +'/'; // 47
Char internally is a struct. "Purpose: This is the value class representing a Unicode character" (char.csms referencesource), and the reason the struct can be implicitly cast is because it implements the IConvertible interface.
public struct Char : IComparable, IConvertible
Specifically, with this piece of code
/// <internalonly/>
int IConvertible.ToInt32(IFormatProvider provider) {
return Convert.ToInt32(m_value);
}
The IConvertible
interface states in a comment in code
// The IConvertible interface represents an object that contains a value. This
// interface is implemented by the following types in the System namespace:
// Boolean, Char, SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64,
// Single, Double, Decimal, DateTime, TimeSpan, and String.
Looking back to the purpose of struct (to be a value representative of a unicode character), it is clear that the intention for this behavior in the language was to provide a way for the value to be converted to supported types. IConvertible
goes on to state
// The implementations of IConvertible provided by the System.XXX value classes
// simply forward to the appropriate Value.ToXXX(YYY) methods (a description of
// the Value class follows below). In cases where a Value.ToXXX(YYY) method
// does not exist (because the particular conversion is not supported), the
// IConvertible implementation should simply throw an InvalidCastException.
Which is explicitly stating that conversions which are not supported throw exceptions. It is also explicitly stated that converting a character to an integer will give the integer value of that character.
The ToInt32(Char) method returns a 32-bit signed integer that represents the UTF-16 encoded code unit of the value argument. Convert.ToInt32 Method (Char)MSDN
All in all, the reasoning for the behavior seems to be self evident. The integer value of the char has meaning as a "UTF-16 encoded code unit". The backslash's value is 47.
As a result of of the value cast present and because char
is a built-in numeric type, the implicit cast to integer from the plus sign is done at compile time. This can be seen with the reuse of the above simple example in a small program (linqpad works to test this)
void Main()
{
int slash = +'/';
Console.WriteLine(slash);
}
Becomes
IL_0000: ldc.i4.s 2F
IL_0002: stloc.0 // slash2
IL_0003: ldloc.0 // slash2
IL_0004: call System.Console.WriteLine
IL_0009: ret
Where the '/'
is simply converted to the hexidecimal value of 2F (47 in decimal) and then used from there.