请考虑以下代码示例:
public abstract class Parent
{
public int val;
public Parent()
{
val = 0;
}
public virtual void foo()
{
inc();
}
public virtual void inc()
{
val = val + 10;
}
}
public class Child : Parent
{
public override void foo()
{
base.foo();
}
public override void inc()
{
val++;
}
}
static void Main(string[] args)
{
Parent p = new Child();
Console.WriteLine("p.val = " + p.val); //Output: p.val = 0
p.foo();
Console.WriteLine("P.val = " + p.val); //Output: p.val = 1
}
我假设没有调用Parent类的inc()
,因为{this}
指针实际指向Child对象,因此将从Parent调用Child的inc()
版本对象的函数foo()
。有没有办法强制Parent的函数foo()
始终调用父函数inc()
就像在C ++中使用::
运算符一样?
答案 0 :(得分:7)
不,您可以非虚拟地调用虚拟方法的唯一方法是使用base.Foo
。当然,您可以在Parent
中编写非虚拟方法,并使Parent.foo()
调用该方法,以及Parent.inc()
的默认实现。
答案 1 :(得分:6)
你过分思考这个问题。
如果您需要非虚拟调度,那么不会首先将方法设为虚拟。
如果您想要虚拟和非虚拟调度,那么制作两种方法,一种是虚拟的,一种是静态的
例如:
class Base
{
protected static void NonVirtualFoo(Base b)
{
// Whatever
}
public virtual void Foo()
{
Base.NonVirtualFoo(this);
}
}
class Derived : Base
{
protected new static void NonVirtualFoo(Derived d)
{
// Whatever
}
public override void Foo()
{
Derived.NonVirtualFoo(this);
Base.NonVirtualFoo(this);
}
}
使用正确的工具完成工作。如果您想要虚拟调度,则调用虚拟方法。如果您想要静态调度,那么调用静态方法。不要试图将锤子用于虚拟方法并使其静态调度;这违背了该工具的整个目的。
答案 2 :(得分:1)
Child实例将调用自己的类型实现。
foo()
调用base.foo()
和base.foo()
调用inc()
,在这种情况下inc()
来自Child,因为该实例是Child类型,并且使用此实现。
答案 3 :(得分:0)
嗯,实际上可能是as said here:
这就是诀窍:
public abstract class Parent
{
public int val;
public Parent()
{
val = 0;
}
public virtual void foo()
{
MethodInfo method = typeof(Parent).GetMethod("inc");
DynamicMethod dm = new DynamicMethod("BaseInc", null, new Type[] { typeof(Parent) }, typeof(Parent));
ILGenerator gen = dm.GetILGenerator();
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Call, method);
gen.Emit(OpCodes.Ret);
var BaseInc = (Action<Parent>)dm.CreateDelegate(typeof(Action<Parent>));
BaseInc(this);
}
public virtual void inc()
{
val = val + 10;
}
}
但它只是概念验证:它是可怕的而完全打破了多态。
我认为你没有理由写这个。