Reputation: 394
I am struggling to understand this scenario with casting. For demo purposes I created these classes:
public interface IFoo {}
public class Foo : IFoo
{
public string Name { get; set; }
}
public class Bar : Foo
{
public string Surname { get; set; }
}
Now, in my Main method I created a static method which returns IFoo:
class Program
{
static void Main()
{
IFoo iFoo = GetIFoo();
Foo foo = (Foo)iFoo;
//the GetType ext method is executed and it returns Bar
if(foo is Foo)
{
Console.WriteLine($"foo is of type: {foo.GetType()}");
}
Console.ReadLine();
}
static IFoo GetIFoo()
{
var bar = new Bar
{
Name = "MyName",
Surname = "MySurname"
}
return bar;
}
}
The question is: even though I'm creating a Bar in the GetIFoo method why is it that if I'm casting the IFoo to Foo, foo's type is Bar and not Foo?
Upvotes: 1
Views: 1098
Reputation: 27962
This is really inheritance 101: The object created is a Bar
and casting just affects how you view it, not what it truly is.
Here you view it as an IFoo
:
IFoo iFoo = GetIFoo();
And here you deliberately view it as a Foo
. It it were not a Foo
, or any of its descendants, you'd get a InvalidCastException
on run-time.
Foo foo = (Foo)iFoo;
A Bar
instance can legally be worked with as Bar
, Foo
, and IFoo
(and as an Object
for the sake of completeness). Regardless how you view the instance, it remains a Bar
.
Upvotes: 1
Reputation: 4394
You are confused between the runtime-type of an object and its compile-time type.
IFoo iFoo = GetIFoo();
In the above line, iFoo
's runtime-type is still Bar
. This is the real type of the object. But if you access the Bar
object via a reference of type IFoo
then the compiler only knows that the type is IFoo
, hence called the compile-time type of the object pointed by reference iFoo
. Note that the compiler lost this type information when the return bar
statement in GetIFoo
was executed.
Foo foo = (Foo)iFoo;
Further down, you can cast it to whatever type you want in the hierarchy of Bar
, anything above and including Bar
will succeed, and the compile time type will be based on what you type-casted it to. But again the runtime type will still stay the same i.e Bar
Upvotes: 1
Reputation: 2936
Because GetType() return type of object. When you explicity cast derived class to base class you didn't create a new instance, you only have new typed reference on existing object. You can see it with code below:
IFoo iFoo = GetIFoo();
Foo foo = (Foo)iFoo;
Console.WriteLine(ifoo.Equals(foo));
Upvotes: 1
Reputation: 476537
Because with the line:
Foo foo = (Foo) iFoo;
you do not convert: a Bar
is a Foo
and an IFoo
all at the same time. So when you cast to (Foo)
the C# interpreter notices that iFoo
is a Bar
and thus leaves the object untouched. The point is, that from now on, the compiler will assume that foo
is indeed a Foo
object, but it can be of any class that extends the Foo
class.
Let's make it more clear with the following example:
interface IDriveable {} // IFoo
class Car : IDriveable { // Foo
string Name {get; set; }
}
class Volkswagen : Car { // Bar
bool CorrectPolution { get; set; }
}
Now if you construct a Volkswagen
, ten obviously that is a Car
and an IDriveable
. But by saying: Car car = (Car) volkswagen;
. You do not alter the volkswagen, you only now let the compiler know that car
is a Car
object.
Upvotes: 1
Reputation: 726479
why is it that if I'm casting the
iFoo
toFoo
,foo
's type isBar
and notFoo
?
This is because casting changes the static type. It has no effect on the dynamic type. foo
's static type is Foo
, but its dynamic type is Bar
.
Each variable has a type known to the compiler (static type) and a type known to the runtime (dynamic type). In some cases these two types are the same, but they do not have to be the same all the time.
Static type is the declared type of the variable. Dynamic type is what you get by calling GetType
after an object is assigned to that variable.
You constructed an example when a static type of a variable does not match its dynamic type: iFoo
has static type of IFoo
, but its dynamic type is Bar
. This is perfectly fine, because Bar
is compatible with IFoo
, because it implements the interface, and also with Foo
, because it extends the class.
Upvotes: 3
Reputation: 13652
Type.GetType
gives you the type of the underlying instance (i.e. the type you specify after new
), no matter what type of variable holds it. Also, foo is Foo
gives true
not only if the actual instance is Foo
, but for every type derived from Foo
.
Upvotes: 1