有没有办法指定范围?

时间:2012-02-22 11:59:14

标签: c# inheritance scope

请考虑以下代码示例:

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 ++中使用::运算符一样?

4 个答案:

答案 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;
    }
}

但它只是概念验证:它是可怕的完全打破了多态

我认为你没有理由写这个。