在 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
Calling the overridden method from the base class in C#
提问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
回答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 someObject
is an A
then A.MyMethod
will be invoked. If someObject
is a B
then B.MyMethod
will be invoked. If someObject
is a BaseClass
and not an instance of a type derived from BaseClass
then BaseClass.MyMethod
will be invoked.
对不起,你完全错了;这将违背虚拟方法的全部意义。如果someObject
是A
然后A.MyMethod
将被调用。如果someObject
是B
然后B.MyMethod
将被调用。如果someObject
是 aBaseClass
而不是从BaseClass
then派生的类型的实例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
N
is invoked with an argument listA
on an instance with a compile-time typeC
and a run-time typeR
(whereR
is eitherC
or a class derived fromC
), the invocation is processed as follows:? First, overload resolution is applied to
C
,N
, andA
, to select a specific methodM
from the set of methods declared in and inherited byC
. This is described in §7.5.5.1.? Then, if
M
is a non-virtual method,M
is invoked.? Otherwise,
M
is a virtual method, and the most derived implementation ofM
with respect to R is invoked.
准确地说,当使用具有编译时类型和运行时类型(其中是或 派生自 的类)的实例上
N
的参数列表调用名为 的方法时,调用的处理方式如下:A
C
R
R
C
C
? 首先,过载分辨率就被应用于
C
,N
和A
,选择一个特定的方法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
M
with respect to a classR
is determined as follows:? If
R
contains the introducing virtual declaration ofM
, then this is the most derived implementation ofM
.? Otherwise, if
R
contains an override ofM
, then this is the most derived implementation ofM
.? Otherwise, the most derived implementation of
M
with respect toR
is the same as the most derived implementation ofM
with respect to the direct base class ofR
.
M
与类相关的虚方法的最派生实现R
如下确定:? 如果
R
包含 的引入虚拟声明M
,则这是 的最派生实现M
。? 否则,如果
R
包含 的覆盖M
,则这是 的最派生实现M
。? 否则,
M
关于R
的最派生实现M
与关于 的直接基类的最派生实现相同R
。
Thus, in our example above with Cat : Animal
and Dog : Animal
, when the parameter a
to Feeder.Feed(Animal)
is an instance of Cat
then Cat.Speak
is the most derived implementation. This is why we will see "Meow!
" and not "i can haz cheezburger?
"
因此,在我们上面使用Cat : Animal
and的例子中Dog : Animal
,当参数a
toFeeder.Feed(Animal)
是Cat
then 的一个实例时,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");
}
}