2010-12-05 167 views
16

如何使用反射调用派生类重写的基本方法?使用反射调用重写的基本方法

class Base 
{ 
    public virtual void Foo() { Console.WriteLine("Base"); } 
} 
class Derived : Base 
{ 
    public override void Foo() { Console.WriteLine("Derived"); } 
} 
public static void Main() 
{ 
    Derived d = new Derived(); 
    typeof(Base).GetMethod("Foo").Invoke(d, null); 
    Console.ReadLine(); 
} 

该代码始终显示“已得到” ......

+0

我创建从@低于格特的答案将允许你这样做的延伸`typeof(Base).GetMethod(“Foo”)。InvokeNotOverride(d,null);`。你可以在这里找到它:http://www.simplygoodcode.com/2012/08/invoke-base-method-using-reflection.html – 2012-08-13 19:18:02

回答

5

即使有反射,你也不能那样做。 C#中的多态性实际上保证将始终调用Derived.Foo(),即使在Derived的实例上也会回退到其基类。

调用Base.Foo()Derived实例的唯一方法是明确地让它从Derived类访问:

class Derived : Base 
{ 
    public override void Foo() 
    { 
     Console.WriteLine("Derived"); 
    } 

    public void BaseFoo() 
    { 
     base.Foo(); 
    } 
} 
+0

也许我需要挖掘DynamicMethod并调用/ callvirt ... – Kii 2010-12-05 07:15:01

+7

也许你需要考虑一下你的设计。没有理由去做这种恶作剧。 – siride 2010-12-05 07:22:10

+0

@siride我不同意。你将如何实现通过返回`base.Foo`构造的委托的序列化? – 2012-05-02 03:51:31

1

思考可以让你看到该对象d有一个“富”的方法,并调用它。

这种方法不过是一个虚方法,这就是为什么你被派生类中获得该方法的实现,因为这是d是什么(除了也正在浇注料的基础)。

没有[直接]从Derived对象调用Base的虚方法。
正如Frederic Hamidi所示,基类的方法可以被Derived类暴露(使用不同的名称),但是这并不真正调用Base的方法,它调用了Derived类的一个方法,调用Base的方法。

虽然这种使Derived类为Base类的方法提供“代理”的方法最终会按照您的要求做,但这样做可能是一个坏主意:设计中可能存在缺陷你的对象模型:这将是一个相当奇怪的用例...

+0

那么是否有任何方法来调用Derived对象上的Base.Foo? – Kii 2010-12-05 06:58:30

+0

不是真的;看我的编辑。 – mjv 2010-12-05 07:19:21

1

你看到什么是多态行为是由设计。当您覆盖虚拟方法时,在被覆盖的类上调用该方法将从VMT调用decendant类的实现。

你的用例是什么,说实话这有点像设计问题。

-2
Base b = (Base)d; 
Console.WriteLine(b.GetType()); //output:Derived 

1)铸造不能改变它的类类型。

class Derived : Base 
{ 
public override void Foo() { Console.WriteLine("Derived"); } 
public Base getBase() 
{ 
    return base; //compiler invalid 
} 
} 

2)以上是无效的,因为你永远不会创建任何Base对象实例,当你创建Derived对象实例。 您创建了Derived class的实例对象,它继承自Base class。 希望,这可以解释为什么你不能调用基函数与派生类对象

31

即使当前的答案已经被接受,它实际上可能,而无需通过使用动态方法这样改变了原来的类:

static void Main(string[] args) 
    { 
     Derived foo = new Derived(); 
     foo.Foo(); 

     MethodInfo method = typeof(Base).GetMethod("Foo"); 
     DynamicMethod dm = new DynamicMethod("BaseFoo", null, new Type[] { typeof(Derived) }, typeof(Derived)); 
     ILGenerator gen = dm.GetILGenerator(); 
     gen.Emit(OpCodes.Ldarg_1); 
     gen.Emit(OpCodes.Call, method); 
     gen.Emit(OpCodes.Ret); 

     var BaseFoo = (Action<Derived>)dm.CreateDelegate(typeof(Action<Derived>)); 
     BaseFoo(foo); 

     Console.ReadKey(); 
    } 

,你可以看到它仍然是相对简单的事

27

后很长一段时间,我终于找到比DynamicMethod的一个更好的解决方案:

class CallOverride 
{ 
    public static void Test() 
    { 
     var obj = new Override(); 
     var method = typeof(object).GetMethod("ToString"); 
     var ftn = method.MethodHandle.GetFunctionPointer(); 
     var func = (Func<string>)Activator.CreateInstance(typeof(Func<string>), obj, ftn); 
     Console.WriteLine(func()); 
    } 
} 

class Override 
{ 
    public override string ToString() 
    { 
     return "Nope"; 
    } 
} 

此解决方案中使用委托的标准构造签名:

public Delegate(object target, IntPtr ftn) 

其中目标是目标实例和FTN是函数指针。 它直接使用基本方法的函数指针调用它,所以委托将指向实际的基本方法,而不是重写的方法。

0

也许纪伊一直在寻找这样的事情

class Base 
{ 
    public virtual void Foo() 
    { 
     Console.WriteLine("Base"); 
    } 
} 

class Derived : Base 
{ 
    // Change virtual with new 
    // public override void Foo() { Console.WriteLine("Derived"); } 
    public new void Foo() 
    { 
     Console.WriteLine("Derived"); 
    } 
} 

static void Main(string[] args) 
{ 
    Derived d = new Derived(); 
    d.Foo();// Output: Derived 

    typeof(Base).GetMethod("Foo").Invoke(d, null);// Output: Base 

    // Or you can cast 
    ((Base)d).Foo();// Output: base 

    Console.ReadLine(); 
}