为什么它做什么该多态C#code打印?做什么、多态、code

2023-09-02 21:55:45 作者:杀死庸碌

最近我给了下面这段code作为排序的拼图,以帮助了解多态性继承在面向对象 - C#

I was recently given the following piece of code as a sort-of puzzle to help understand Polymorphism and Inheritance in OOP - C#.

// No compiling!
public class A
{
     public virtual string GetName()
     {
          return "A";
     }
 }

 public class B:A
 {
     public override string GetName()
     {
         return "B";
     }
 }

 public class C:B
 {
     public new string GetName()
     {
         return "C";
     }
 }

 void Main()
 {
     A instance = new C();
     Console.WriteLine(instance.GetName());
 }
 // No compiling!

现在,经过一个很长很长的聊天与谁$ P $其他开发商psented的困扰,我知道输出是什么,但我不会破坏它。我真的有唯一的问题是我们如何达到那个输出,如何在code步进通过,什么继承什么,等等。

Now, after a long, long chat with the other developer who presented the puzzle, I know what the output is, but I wont spoil it for you. The only issue I'm really having is how we get to that output, how the code steps through, what's inheriting what, etc.

我觉得 C 将返回因为这似乎是被定义的类。然后,我经历了我的头是否 B 将返回,因为C继承了 B - 但 B 也继承了 A (这是我弄糊涂了!)。

I thought C would be returned as that seems to be the class that is defined. Then I went through my head as to whether B would be returned because C inherits B - but B also inherits A (which is where I got confused!).

任何人都可以解释如何多态和继承发挥作用,检索输出,最终显示在屏幕上?

Could anyone explain how polymorphism and inheritance play their part in retrieving the output, eventually displayed on screen?

推荐答案

要考虑这个正确的方法是想象,每类要求它的对象有一定数目的槽的;这些槽被充满的方法。这个问题:什么方法实际上被调用?需要你弄清楚两件事情:

The correct way to think about this is to imagine that every class requires its objects to have a certain number of "slots"; those slots are filled with methods. The question "what method actually gets called?" requires you to figure out two things:

什么是每个插槽的内容? 在哪个插槽叫?

让我们首先考虑的插槽。有两个时隙。 A的所有实例都需要有一个插槽,我们会打电话给GetNameSlotA。对C所有实例都需要有一个插槽,我们会打电话给GetNameSlotC。这就是新是指在C中的声明 - 这意味着我希望有一个新的槽。相比于上声明,B,这意味着覆盖我不想要一个新的插槽,我想重新使用GetNameSlotA。

Let's start by considering the slots. There are two slots. All instances of A are required to have a slot we'll call GetNameSlotA. All instances of C are required to have a slot we'll call GetNameSlotC. That's what the "new" means on the declaration in C -- it means "I want a new slot". Compared to the "override" on the declaration in B, which means "I do not want a new slot, I want to re-use GetNameSlotA".

当然,C继承了A,所以C还必须有一个插槽GetNameSlotA。因此,将C的实例有两个插槽 - GetNameSlotA,和GetNameSlotC。 A或B的实例这是不是C有一个插槽,GetNameSlotA。

Of course, C inherits from A, so C must also have a slot GetNameSlotA. Therefore, instances of C have two slots -- GetNameSlotA, and GetNameSlotC. Instances of A or B which are not C have one slot, GetNameSlotA.

现在,什么进入这两个插槽,当你创建一个新的C?有三种方法,我们称之为GetNameA,GetNameB和GetNameC。

Now, what goes into those two slots when you create a new C? There are three methods, which we'll call GetNameA, GetNameB, and GetNameC.

一个的声明说:把GetNameA在GetNameSlotA。 A是C的父类,所以A的规则适用于以下。

The declaration of A says "put GetNameA in GetNameSlotA". A is a superclass of C, so A's rule applies to C.

B的声明中说:把GetNameB在GetNameSlotA。 B是C的父类,所以B的规则适用于C的情况下,现在,我们有A和B,B之间的矛盾是比较派生类型,因此它赢 - B的规则的重写的A的规则。因此,这个词在声明中忽略。

The declaration of B says "put GetNameB in GetNameSlotA". B is a superclass of C, so B's rule applies to instances of C. Now we have a conflict between A and B. B is the more derived type, so it wins -- B's rule overrides A's rule. Hence the word "override" in the declaration.

C的声明说:把GetNameC在GetNameSlotC。

The declaration of C says "put GetNameC in GetNameSlotC".

因此​​,你的新的C将有两个插槽。 GetNameSlotA将包含GetNameB和GetNameSlotC将包含GetNameC。

Therefore, your new C will have two slots. GetNameSlotA will contain GetNameB and GetNameSlotC will contain GetNameC.

我们现在已经确定什么样的方法是什么插槽,所以我们已经回答了第一个问题。

We've now determined what methods are in what slots, so we've answered our first question.

现在我们来回答第二个问题。叫什么位置?

Now we have to answer the second question. What slot is called?

想想看,就像你的编译器。你具有可变的。所有你知道的是,这是A型要求您解决该变量的方法调用。你看看插槽可在A,唯一的插槽,你可以找到匹配的GetNameSlotA。你不知道GetNameSlotC,因为你只有A型的变量;为什么你会找插槽,只适用于C 2

Think about it like you're the compiler. You have a variable. All you know about it is that it is of type A. You're asked to resolve a method call on that variable. You look at the slots available on an A, and the only slot you can find that matches is GetNameSlotA. You don't know about GetNameSlotC, because you only have a variable of type A; why would you look for slots that only apply to C?

因此​​,这是一个呼吁无论是在GetNameSlotA。我们已经确定了在运行时,GetNameB将在该插槽。因此,这是一个呼叫GetNameB

Therefore this is a call to whatever is in GetNameSlotA. We've already determined that at runtime, GetNameB will be in that slot. Therefore, this is a call to GetNameB.

这里的关键外卖是,在C#中重载选择一个插槽并生成调用无论发生什么事是在该插槽。

The key takeaway here is that in C# overload resolution chooses a slot and generates a call to whatever happens to be in that slot.