So I don't have an in-depth knowledge of how data is stored in the .NET Framework in terms of custom types, but I was looking for an explanation on how the casting system is working.
For example, if one were to do an explicit cast from a ValueType Struct like Char into Byte as follows:
char C = '#';
byte B = (byte)C;
Console.WriteLine(B.GetType()); // Outputs "Byte"
I would be told that B is a Byte, which makes perfect sense.
Now say I cast from a Custom Class Flower to its base Class Plant, why does the output reveal the derived class regardless of the cast as follows:
class Plant{}
class Flower:Plant{}
.
Flower Rose = new Flower();
Plant RoseBush = (Plant)Rose;
Console.WriteLine(RoseBush.GetType()); //Outputs Flower
Plant Rose = new Flower();
Plant RoseBush = (Plant)Rose;
Console.WriteLine(RoseBush.GetType()); //Outputs Flower as well
I guess my question is, why doesn't the type expose the current type of the custom type, that being Plant, and why does this differ from the Value Types at the beginning?
Also, why is the two examples with the flower and plants, although written differently on the first line, output the same thing?
The result of the first cast is a different value. It's now a byte
not a char
.
The second cast is a reference conversion. The result is the same set of bits - a reference to the same object - just with a different compile-time type. GetType()
returns the actual execution-time type of the object, which is the same in both cases (because it's the same object).
You can observe this in your example:
// Variable names modified to follow normal conventions
Flower rose = new Flower();
Plant roseBush = (Plant) rose;
Console.WriteLine(ReferenceEquals(rose, roseBush)); // True
Casts for reference types can result in different values, mind you, if they're custom conversions - but those aren't "reference conversions" in language spec terminology. For example:
XElement element = new XElement("name", "value");
string value = (string) element;
Here value
really isn't a reference to the same object as element
- it's a reference to a string
object instead of an XElement
object, via the explicit conversion to string
defined by XElement
.
The C# cast syntax does different things in different cases. When you talk about a class and base-class / sub-class / interface, it is a reference preserving cast - all you're actually doing is a type check (and even that is only in the case where the compiler doesn't know that it must work - it is omitted when casting a sub-type to the base-type, for example). In this case, the only thing that changes is the type that the compiler / JIT is thinking of.
However, there are also type conversions. Those can be inbuilt (as is the case for primitives such as byte
/ char
), or they can be supplied as custom conversion operators (via the implicit
or explicit
operator keywords). In that case, it is up to the code what happens (it could be anything).
So: the difference here is that one is an inbuilt primitive conversion, and one is a reference-preserving type check.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With