在 C# 中从基类调用被覆盖的方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2299367/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-07 01:13:40  来源:igfitidea点击:

Calling the overridden method from the base class in C#

c#inheritancemethodsvirtualoverriding

提问by David

Given the following C# class definitions and code:

鉴于以下 C# 类定义和代码:


public class BaseClass
{
    public virtual void MyMethod()
    {
        ...do something...
    }
}

public class A : BaseClass
{
    public override void MyMethod()
    {
        ...do something different...
    }
}

public class B : BaseClass
{
    public override void MyMethod()
    {
        ...do something different...
    }
}

public class AnotherObject
{
    public AnotherObject(BaseClass someObject)
    {
        someObject.MyMethod(); //This calls the BaseClass method, unfortunately.
    }
}

I would like to call the MyMethod() that is actually found in A or B, assuming the object passed in is actually an instance of A or B, not that which is found in BaseClass. Short of doing something like this:

我想调用实际上在 A 或 B 中找到的 MyMethod(),假设传入的对象实际上是 A 或 B 的实例,而不是在 BaseClass 中找到的实例。没有做这样的事情:


public class AnotherObject
{
    public AnotherObject(BaseClass someObject)
    {
        A temp1 = someObject as A;
        if (A != null)
        {
            A.MyMethod();
        }

        B temp2 = someObject as B;
        if (B != null)
        {
            B.MyMethod();
        }
    }
}

How can I do it?

我该怎么做?

采纳答案by JonathanK

Which method is called is determined via polymorphism on the type that is passed into the AnotherObject constructor:

调用哪个方法是通过传递到另一个对象构造函数的类型的多态性来确定的:

AnotherObject a = new AnotherObject(new A()); // invokes A.MyMethod() 
AnotherObject b = new AnotherObject(new B()); // invokes B.MyMethod() 
AnotherObject c = new AnotherObject(new BaseClass()); //invokes BaseClass.MyMethod() 

回答by Yuriy Faktorovich

If someObject passed in is class A, then A.MyMethod is called, not the base class implementation. Also look at the iskeyword.

如果传入的 someObject 是类 A,则调用 A.MyMethod,而不是基类实现。还要看is关键字。

回答by Joel Etherton

Because you've typed it as a BaseClass instead of an A or a B, the baseclass is the begin point for the method calls.

因为您已将其键入为 BaseClass 而不是 A 或 B,所以基类是方法调用的起点。

You might try using a generic:

您可以尝试使用泛型:

public class AnotherObject 
{ 
    public AnotherObject<T>(T someObject) where T : BaseClass
    { 
        someObject.MyMethod(); //This calls the BaseClass method, unfortunately. 
    } 
} 

I'm not sure how well this will fly in the constructor, but you might be able to move this to a different method.

我不确定这在构造函数中的效果如何,但您可以将其移至不同的方法。

回答by jason

Sorry, but you are completely mistaken; this would go against the entire point of virtual methods. If someObjectis an Athen A.MyMethodwill be invoked. If someObjectis a Bthen B.MyMethodwill be invoked. If someObjectis a BaseClassand not an instance of a type derived from BaseClassthen BaseClass.MyMethodwill be invoked.

对不起,你完全错了;这将违背虚拟方法的全部意义。如果someObjectA然后A.MyMethod将被调用。如果someObjectB然后B.MyMethod将被调用。如果someObject是 aBaseClass而不是从BaseClassthen派生的类型的实例BaseClass.MyMethod将被调用。

Let's use everyone's favorite example:

让我们使用每个人都喜欢的例子:

class Animal {
    public virtual void Speak() {
        Console.WriteLine("i can haz cheezburger?");
    } 
}
class Feeder {
    public void Feed(Animal animal) { animal.Speak(); }
}
class Cat : Animal {
    public override void Speak() { Console.WriteLine("Meow!"); }
}
class Dog : Animal {
    public override void Speak() { Console.WriteLine("Woof!"); }
}

Then:

然后:

Animal a = new Animal();
Animal c = new Cat();
Animal d = new Dog();
Feeder f = new Feeder();
f.Feed(a);
f.Feed(c);
f.Feed(d);

This will print:

这将打印:

i can haz cheezburger?
Meow!
Woof!

Again, this is the entire point of virtual methods.

同样,这是虚拟方法的全部意义所在。

Further, we can go to the specification. From 10.6.3 (Virtual methods)

此外,我们可以转到规范。从 10.6.3(虚拟方法)

In a virtual method invocation, the run-time typeof the instance for which that invocation takes place determines the actual method implementation to invoke.

在虚拟方法调用中,发生该调用的实例的运行时类型决定了要调用的实际方法实现。

(Bolding and italics in original.)

(原文为粗体和斜体。)

In precise terms, when a method named Nis invoked with an argument list Aon an instance with a compile-time type Cand a run-time type R(where Ris either Cor a class derived from C), the invocation is processed as follows:

? First, overload resolution is applied to C, N, and A, to select a specific method Mfrom the set of methods declared in and inherited by C. This is described in §7.5.5.1.

? Then, if Mis a non-virtual method, Mis invoked.

? Otherwise, Mis a virtual method, and the most derived implementation of Mwith respect to R is invoked.

准确地说,当使用具有编译时类型和运行时类型(其中是或 派生自 的类)的实例上N的参数列表调用名为 的方法时,调用的处理方式如下:ACRRCC

? 首先,过载分辨率就被应用于CNA,选择一个特定的方法M从该组中声明和继承的方法C。这在 §7.5.5.1 中有描述。

? 然后,如果M是非虚方法,M则被调用。

? 否则,M是一个虚方法,并且M调用关于 R的最派生的实现。

(Bolding not in original.)

(粗体不是原文。)

Then, we need the definition of "most derived implementation of M." This is a nice recursive definition:

然后,我们需要“最衍生的 实现”的定义M。这是一个很好的递归定义:

The most derived implementation of a virtual method Mwith respect to a class Ris determined as follows:

? If Rcontains the introducing virtual declaration of M, then this is the most derived implementation of M.

? Otherwise, if Rcontains an override of M, then this is the most derived implementation of M.

? Otherwise, the most derived implementation of Mwith respect to Ris the same as the most derived implementation of Mwith respect to the direct base class of R.

M与类相关的虚方法的最派生实现R如下确定:

? 如果R包含 的引入虚拟声明M,则这是 的最派生实现M

? 否则,如果R包含 的覆盖M,则这是 的最派生实现M

? 否则,M关于R的最派生实现M与关于 的直接基类的最派生实现相同R

Thus, in our example above with Cat : Animaland Dog : Animal, when the parameter ato Feeder.Feed(Animal)is an instance of Catthen Cat.Speakis the most derived implementation. This is why we will see "Meow!" and not "i can haz cheezburger?"

因此,在我们上面使用Cat : Animaland的例子中Dog : Animal,当参数atoFeeder.Feed(Animal)Catthen 的一个实例时,Cat.Speak是最派生的实现。这就是为什么我们会看到“ Meow!”而不是“ i can haz cheezburger?

回答by slugster

If MyMethod()is abstract on the base class, then the version in the derived classes will be used. So if you don't need to call the instance in the base class, this would be an option.

如果MyMethod()在基类上是抽象的,则将使用派生类中的版本。因此,如果您不需要在基类中调用实例,这将是一个选项。

    static void Main(string[] args)
    {

        A classA = new A();
        B classB = new B();

        DoFunctionInClass(classA);
        DoFunctionInClass(classB);
        DoFunctionInClass(classA as BaseClass);

        Console.ReadKey();
    }

    public static void DoFunctionInClass(BaseClass c) 
    {
        c.MyMethod();
    }



public abstract class BaseClass
{
    public abstract void MyMethod();
}


public class A : BaseClass
{
    public override void MyMethod()
    {
        Console.WriteLine("Class A");
    }
}

public class B : BaseClass
{
    public override void MyMethod()
    {
        Console.WriteLine("Class B");
    }
}