Use reflection to invoke an overridden base method
You can't do that, even with reflection. Polymorphism in C# actually guarantees that Derived.Foo()
will always be called, even on an instance of Derived
cast back to its base class.
The only way to call Base.Foo()
from a Derived
instance is to explicitly make it accessible from the Derived
class:
class Derived : Base
{
public override void Foo()
{
Console.WriteLine("Derived");
}
public void BaseFoo()
{
base.Foo();
}
}
How can I call a base class's method via reflection?
EDIT: OK, so a bit of clarification; you're not trying to call the base class's implementation from outside either class. Instead, from within the overridden class, you want to reflectively call the parent method's implementation.
... Why? Your object statically knows what it is, and therefore statically knows what its base class is. You can't have two base classes, and you can't dynamically "assign" a base class to a pre-existing child class.
To answer your question, you can't. Any attempt to reflectively call "Foo" using the current instance will infinitely recurse, because the invocation of a MethodInfo makes the method call as if it were coming from outside ('cause it is), and so the runtime will obey inheritance/overriding behaviors. You would have to use the IL hack from the related question.
Invoke an overridden instance method using reflection in java
MethodHandles can be used to invoke a superclass method:
https://www.baeldung.com/java-method-handles
Call method of the derived class through reflection. Possible or no?
The GetType
method will give you the real type of Foo
at runtime:
public class ClassThatUses
{
public Foo Foo { get; set; }
public void CallPrepare()
{
// Foo.Prepare();
Foo.GetType().GetMethod("Prepare").Invoke(Foo, null);
}
}
Following your edit, if you want to find the runtime type of Foo
for a particular instance of ClassThatUses
then you'll need to use GetValue
to interrogate the value of Foo
on that instance:
ClassThatUses o = new ClassThatUses() { Foo = new Bar() };
// Type fooType = o.Foo.GetType();
Type fooType = o.GetType().GetProperty("Foo").GetValue(o, null).GetType();
Detect if a method was overridden using Reflection (C#)
Given the type Test1
, you can determine whether it has its own implementation declaration of TestMe
:
typeof(Test1).GetMethod("TestMe").DeclaringType == typeof(Test1)
If the declaration came from a base type, this will evaluate false.
Note that since this is testing declaration, not true implementation, this will return true if Test1
is also abstract and TestMe
is abstract, since Test1
would have its own declaration. If you want to exclude that case, add && !GetMethod("TestMe").IsAbstract
How to force inheriting class's method implementation to call base method before invoke own implantation?
I don't think that you can enforce the inheriting classes to always first call a method's super implementation, but:
Normally I use a Template method pattern for cases like this:
public abstract class TemplateEnforcer
{
private void TheSame()
{
Console.WriteLine("Everyone calls me;");
}
public void TemplateMethod()
{
this.TheSame();
this.NeedsImplementation();
}
protected abstract void NeedsImplementation();
}
public class TemplateImplementer : TemplateEnforcer
{
protected override void NeedsImplementation()
{
Console.WriteLine("Implemented in TemplateImplementer");
}
}
Code output for this call new TemplateImplementer().TemplateMethod()
:
//Everyone calls me;
//Implemented in TemplateImplementer
Template method pattern benefits:
- Implementation of abstract method is forced.
- The code is kept DRY.
- Bugs are avoided and devs are guided in their development.
Reflection: How to get base method (not original method)?
Walking inheritance tree
You could use some reflection and walk inheritence tree of given type, type by type:
public static Type GetMethodDeclaringTypeClosestInHierarchy(MethodInfo derivedTypeMethod)
{
//Method is not virtual, you have the only definition in inheritance tree
if (!derivedTypeMethod.IsVirtual) return derivedTypeMethod.DeclaringType;
var baseType = derivedTypeMethod.DeclaringType.BaseType;
while (baseType != null)
{
//Check if in base type there is a method
if (baseType.GetMethods().Any(baseTypeMethod =>
//that has same base definition like then one we're checking
baseTypeMethod.GetBaseDefinition() == derivedTypeMethod.GetBaseDefinition()
//and is actually overriden in baseType
&& baseTypeMethod.DeclaringType == baseType))
{
return baseType;
}
//If not, go on higher in inheritance tree
baseType = baseType.BaseType;
}
//Found nothing
return derivedTypeMethod.DeclaringType;
}
Ambiguous method name
Problem with Scott's answer is that when you have two methods with different signatures but same name in inheritance tree:
class A
{
public virtual void Func() { }
public virtual string Func(string test) { return ""; }
}
class B : A
{
public override string Func(string test) => base.Func(test);
public override void Func() => base.Func();
}
class C : B
{
public override void Func() => base.Func();
}
you will get an System.Reflection.AmbiguousMatchException: 'Ambiguous match found.'
on
typeof(B).GetMethod("Func",
BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public);
Usage
static void Main(string[] args)
{
var type = typeof(C);
//This will throw with multiple methods of given name:
var method1 = type.GetMethod("Func");
//This will not but you need to be pretty explicit on what you're searching for
var method2 = type.GetMethods().SingleOrDefault(m => m.Name == "Func" && m.ReturnType == typeof(void));
var result = GetMethodDeclaringTypeClosestInHierarchy(method2);
Console.WriteLine(result);
Console.ReadKey();
}
Related Topics
No Console Output When Using Allocconsole and Target Architecture X86
Choose One of Many Internet Connections for an Application
How to Return an Anonymous Type from a Method
How to Get the Full Url of the Page I am on in C#
How to Discover the "Path" of an Embedded Resource
Check If Value Exists in Datatable
Should You Declare Methods Using Overloads or Optional Parameters in C# 4.0
Handling Executescalar() When No Results Are Returned
How to Find System.Web.Helpers, System.Web.Webpages, and System.Web.Razor
Windows 7 and Vista Uac - Programmatically Requesting Elevation in C#
Identityserver4 Role Based Authorization for Web API with ASP.NET Core Identity
How to Sort a String of Text Followed by a Number Using Linq
Passing Data to Master Page in ASP.NET MVC
Convert String to Hex-String in C#
How to Return a Custom Http Status Code from a Wcf Rest Method