While implementing support for interface default implementations in NUKE we’ve added the new fluent methods Base
and Inherit
. In order to let an overridden target inherit from its base declaration (or a re-implemented target with default implementation), we needed to make non-virtual calls using reflection. This wasn’t exactly easy, since even when reflecting on a member through its declaring type, it will follow the principle of polymorphism and call the member virtual. With a bit of Stack Overflow, we ended up implementing the following generic method:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static TResult GetValueNonVirtual<TResult>(this MemberInfo member, object obj, params object[] arguments)
{
ControlFlow.Assert(member is PropertyInfo || member is MethodInfo, "member is PropertyInfo || member is MethodInfo");
var method = member is PropertyInfo property
? property.GetMethod
: (MethodInfo) member;
var funcType = Expression.GetFuncType(method.GetParameters().Select(x => x.ParameterType)
.Concat(method.ReturnType).ToArray());
var functionPointer = method.NotNull("method != null").MethodHandle.GetFunctionPointer();
var nonVirtualDelegate = (Delegate) Activator.CreateInstance(funcType, obj, functionPointer)
.NotNull("nonVirtualDelegate != null");
return (TResult) nonVirtualDelegate.DynamicInvoke(arguments);
}
Using the GetValueNonVirtual
method, we can use any property or method reflected from a base type, and bypass their overrides:
1
2
var method = typeof(object).GetMethod("ToString").Single();
var value = method.GetValueNonVirtual(dto);
Reflection FTW! 😎