Reputation: 27
Class A
{
string name = "a";
public virtual void Rename(){//rename name to aaa}
}
Class B:A
{
string name = "b";
public override void Rename(){//rename name to bbb}
}
void Main()
{
B objB = new B();
A objA = objB as A;
print(objB.name);// b
print(objA.name);// a
objA.Rename();
print(objB.name);// bbb
print(objA.name);// a
}
Why when I use objA.Rename()
, it actually uses the override version written in class B. What is objA
in the end. If it is A, then why it uses the override version. If it is B then why objA.name
is a not bbb;
Upvotes: 2
Views: 126
Reputation: 32740
First of all, you must understand that casting in c# is a name that is used for very different conversions and can create confusion.
The casting you are asking about is technically named a reference conversion. Reference conversions are identity preserving conversions, this means that the object does not change, what changes is the type of the reference:
var s = “Hello”;
var o = (object)s;
var b = ReferenceEquals(s, o); //returns true
Here, s
and o
refer to the exact same object, the only thing that changes is the type of the reference.
It’s important to note that reference conversions are automatically provided by the compiler, you can’t define a user defined identity preserving conversion, you will get a compiler error.
What are the most common reference conversions you will encounter? Any conversion between types and subtypes or types and implemented interfaces, etc.
Now consider the following seemingly similar code:
var l = 1L;
var i = (int)l;
This code is radically different than the previous one. Why? Because the cast here is not a reference conversion. This actually calls a user defined explicit
cast operator implemented in System.Int32
. i
and l
are different objects.
Another important conversions in c# are boxing and unboxing conversions. These are not identity preserving but they do share common ”feature” as far as not being able to implement user defined boxing or unboxing conversions. Boxing refers to converting a value type into a assignment compatible reference type and unboxing is the opposite operation:
var i = 1;
var o = (object)i; //boxing
var ii = (int)o; //unboxing
How do you know at first glance if it’s a reference conversion or not? Well, as long as you know the hierarchy of the involved types. interfaces, etc. you should be able to reason it out.
Upvotes: 0
Reputation: 8163
The object never changes. In memory, it is always a B
, no matter how you choose to interact with it. The way to know this is the case is to just call .GetType()
on your variables and they will all tell you each one is an instance of B
.
B objB = new B();
A objA = objB as A;
Console.WriteLine(objB.GetType()) // B
Console.WriteLine(objA.GetType()) // B
The reason you get "a"
at the end, is because you have two different declarations of name
. meaning: A.name
is a totally different address than B.name
To fix this, you could just remove string name = "b";
from B
and instead put name = "b";
into it's constructor.
Class A
{
string name = "a";
public virtual void Rename(){//rename name to aaa}
}
Class B:A
{
public override void Rename(){//rename name to bbb}
public B() { name = "b"; }
}
Another way to think about this is that if you call base.name
inside of B
i am sure you will get the same result of "a"
, showing you that B
actually has two separate declarations of name
.
Upvotes: 3