简体   繁体   English

在 C# 中将派生类向上转换为基类

[英]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 to Foo , foo 's type is Bar and not Foo ?为什么如果我将iFooFoofoo的类型是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.这完全没问题,因为BarIFoo兼容,因为它实现了接口,也与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实例可以合法地作为BarFooIFoo (为了完整起见,也可以作为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 ,十个显然是CarIDriveable 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.请注意,在执行GetIFooreturn 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM