有没有办法调用重写方法的父版本?

Is there any way to call the parent version of an overridden method? (C# .NET)

在下面的代码中,我尝试了两种方法来访问method2的父版本,但结果总是2。在不修改这两个类的情况下,是否有任何方法可以从ChildClass实例获得1结果?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class ParentClass
{
    public int methodOne()
    {
        return methodTwo();
    }

    virtual public int methodTwo()
    {
        return 1;
    }
}

class ChildClass : ParentClass
{
    override public int methodTwo()
    {
        return 2;
    }
}

class Program
{
    static void Main(string[] args)
    {
        var a = new ChildClass();
        Console.WriteLine("a.methodOne():" + a.methodOne());
        Console.WriteLine("a.methodTwo():" + a.methodTwo());
        Console.WriteLine("((ParentClass)a).methodTwo():"
         + ((ParentClass)a).methodTwo());
        Console.ReadLine();
    }
}

更新chrisw发布此:

From outside the class, I don't know
any easy way; but, perhaps, I don't
know what happens if you try
reflection: use the Type.GetMethod
method to find the MethodInfo
associated with the method in the
ParentClass, and then call
MethodInfo.Invoke

那个答案被删除了。我想知道那个黑客是否可以工作,只是出于好奇。


ChildClass.methodTwo()的内部,可以调用base.methodTwo()

在班外,调用((ParentClass)a).methodTwo())将调用ChildClass.methodTwo。这就是虚拟方法存在的全部原因。


在IL级别,您可能会发布一个call而不是callvirt,并完成任务-但如果我们将自己限制在c-p(编辑darn!运行时会阻止您:VerificationException:"操作可能会破坏运行时的稳定性。";删除virtual,它工作得很好;聪明了一半……)

ChildClass类型中,您可以使用base.methodTwo()—但是,这在外部是不可能的。你也不能下降超过一个级别——没有base.base.Foo()支持。

但是,如果使用方法隐藏禁用多态性,则可以得到所需的答案,但原因不好:

1
2
3
4
5
6
7
class ChildClass : ParentClass
{
    new public int methodTwo() // bad, do not do
    {
        return 2;
    }
}

现在,根据变量是定义为ChildClass还是ParentClass,您可以从同一对象得到不同的答案。


如前所述,如果需要在生产代码中调用"base.base",那么类设计就有问题。但是,如果您在使用无法编译的外部库的同时调试或搜索某些WorkarRounds,那么使用此技术是非常合法的。令人不快的是,C没有直接提供这个选项。不过,您可以将Kenneth Xu解决方案与IL生成器一起使用并发射。它起作用了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class A { public virtual string foo() { return"A"; } }

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

// now in class C
class C : B {}      
// we can call virtual method"foo" from A using following code
MethodInfo fooA = typeof(A).GetMethod("foo", BindingFlags.Public | BindingFlags.Instance);

DynamicMethod baseBaseFoo = new DynamicMethod(
           "foo_A",
            typeof(string),
            new[] { typeof(A) },
            typeof(A));
        ILGenerator il = baseBaseFoo.GetILGenerator();
        il.Emit(OpCodes.Ldarg, 0);
        il.EmitCall(OpCodes.Call, fooA, null);
        il.Emit(OpCodes.Ret);

// call foo() from class A, it returns"A"
(string)baseBaseFoo.Invoke(null, new object[] { this });

有关参考和完整样本,请参见http://kennethxu.blogspot.cz/2009/05/cnet-calling-grandrent-virtual-method.html

谢谢许肯尼斯!


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Parent
{
    public string Method()
    {
       return"parent";

    }
}

public class Child:Parent
{
    public string Method()
    {
       return"child";

    }
}

上面的代码成功地重写了父方法,但父方法的值仍然保持不变。

可以使用下面的代码从父类和子类返回值-

1
2
Child child = new Child();
string result = (((Parent)child).Method()) + child.Method();

But Visual Studio will show you a warning in Compile Time.


正如马克·格雷弗所说,不,不是外部的。但这是我用过的另一个黑客。ChildClass可以从ParentClass中暴露methodTwo()供自身使用或供外部使用。在你的情况下:

1
2
3
4
5
6
7
8
9
10
11
12
13
class ChildClass : ParentClass {
    override public int methodTwo() {
        return 2;
    }
    public int ParentClass_methodTwo() {
        return base.methodTwo();
    }
}

// Now instead of
Console.WriteLine("ParentClass methodTwo:" + ((ParentClass)a).methodTwo());
// use
Console.WriteLine("ParentClass methodTwo:" + a.ParentClass_methodTwo());

在我的例子中,子类引入了对等的概念,我需要它对methodTwo()的覆盖来调用对等的基础版本。但是,通过覆盖它,它隐藏了它…还是这样?这项技术被拯救了。

1
2
3
4
5
6
7
8
9
class ChildClass : ParentClass {
    ChildClass peer;
    override public int methodTwo() {
        return peer.ParentClass_methodTwo();
    }
    private int ParentClass_methodTwo() {
        return base.methodTwo();
    }
}

据我所知,一旦方法被重写,就不能调用父方法。


我在寻找帮助的过程中偶然发现了这个问题,最终找到了自己调用方法的祖先版本的方法。这是一个假设您可以编辑祖先类的工作:

将祖先类中存在问题的功能放入带有必要参数的静态方法中。该类中的方法可以调用它,因此它不需要复制功能,并且如果需要,子类可以通过静态方法调用该功能。这样,即使在方法中也可以这样做,并且可以引用它想要调用的特定类。此外,它还可以访问比父母更远的祖先,这是使用"基地"的限制。


我认为除非您直接创建parentclass实例,否则是不可能的。这是遗传的本质,多态性…