[英]Upcasting derived class to base class in C#
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:现在,在我的 Main 方法中,我创建了一个返回 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?问题是:即使我在 GetIFoo 方法中创建了一个 Bar,为什么如果我将 IFoo 强制转换为 Foo,foo 的类型是 Bar 而不是 Foo?
why is it that if I'm casting the
iFoo
toFoo
,foo
's type isBar
and notFoo
?为什么如果我将iFoo
为Foo
,foo
的类型是Bar
而不是Foo
?
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
. foo
的静态类型是Foo
,但它的动态类型是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.动态类型是在将对象分配给该变量后通过调用GetType
获得的。
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
.当变量的静态类型与其动态类型不匹配时,您构造了一个示例: iFoo
静态类型为IFoo
,但其动态类型为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.这完全没问题,因为Bar
与IFoo
兼容,因为它实现了接口,也与Foo
兼容,因为它扩展了类。
This is really inheritance 101 : The object created is a Bar
and casting just affects how you view it, not what it truly is .这真的是继承 101 :创建的对象是一个Bar
并且强制转换只会影响您查看它的方式,而不是它的真正含义。
Here you view it as an IFoo
:在这里,您将其视为IFoo
:
IFoo iFoo = GetIFoo();
And here you deliberately view it as a Foo
.在这里,您故意将其视为Foo
。 It it were not a Foo
, or any of its descendants, you'd get a InvalidCastException
on run-time.如果它不是Foo
或其任何后代,您会在运行时得到InvalidCastException
。
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). Bar
实例可以合法地作为Bar
、 Foo
和IFoo
(为了完整起见,也可以作为Object
使用)。 Regardless how you view the instance, it remains a Bar
.无论您如何查看实例,它仍然是一个Bar
。
Type.GetType
gives you the type of the underlying instance (ie the type you specify after new
), no matter what type of variable holds it. Type.GetType
为您提供基础实例的类型(即您在new
之后指定的类型),无论它是什么类型的变量。 Also, foo is Foo
gives true
not only if the actual instance is Foo
, but for every type derived from Foo
.此外, foo is Foo
给人true
不是只有在实际的实例是Foo
,但对来源于每一个类型Foo
。
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.你不转换:一个Bar
是一个Foo
和一个IFoo
。 So when you cast to (Foo)
the C# interpreter notices that iFoo
is a Bar
and thus leaves the object untouched.因此,当您iFoo
为(Foo)
,C# 解释器会注意到iFoo
是一个Bar
,因此该对象保持不变。 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.关键是,从现在开始,编译器将假定foo
确实是一个Foo
对象,但它可以是扩展Foo
类的任何类。
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
.现在,如果您构建一辆Volkswagen
,十个显然是Car
和IDriveable
。 But by saying: Car car = (Car) volkswagen;
但是通过说: Car car = (Car) volkswagen;
. . You do not alter the volkswagen, you only now let the compiler know that car
is a Car
object.你没有改变大众汽车,你只是现在让编译器知道car
是一个Car
对象。
Because GetType() return type of object.因为GetType()返回对象的类型。 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));
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
.在上面的行中, iFoo
的运行时类型仍然是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
.但是,如果您通过IFoo
类型的引用访问Bar
对象,则编译器只知道该类型是IFoo
,因此称为引用iFoo
指向的对象的编译时类型。 Note that the compiler lost this type information when the return bar
statement in GetIFoo
was executed.请注意,在执行GetIFoo
的return bar
语句时,编译器丢失了此类型信息。
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.再往下,您可以将其强制转换为Bar
层次结构中您想要的任何类型,任何高于和包括Bar
类型都将成功,并且编译时类型将基于您将其强制转换为的类型。 But again the runtime type will still stay the same ie Bar
但同样,运行时类型仍将保持不变,即Bar
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.