How can I handle generic method invocations in my DynamicObject? - c#

I'm trying to construct a DynamicObject that is able to handle generic method invocations, but it seems that the needed API - although present in RC versions of 4.0 Framework - has been marked internal in RTM (namely, CSharpInvokeMemberBinder is now internal). Is there an equivalent for this code that would work in 4.0 RTM?
public class TransparentObject<T> : DynamicObject {
private readonly T target;
public TransparentObject(T target) {
this.target = target;
}
public override bool TryInvokeMember(
InvokeMemberBinder binder, object[] args, out object result) {
var csBinder = binder as CSharpInvokeMemberBinder;
var method = typeof(T).GetMethod(binder.Name, BindingFlags.Public
| BindingFlags.NonPublic | BindingFlags.Instance);
if (method == null)
throw new MissingMemberException(string.Format(
"Method '{0}' not found for type '{1}'", binder.Name, typeof(T)));
if (csBinder.TypeArguments.Count > 0)
method = method.MakeGenericMethod(csBinder.TypeArguments.ToArray());
result = method.Invoke(target, args);
return true;
}
}
(Code taken from http://bugsquash.blogspot.com/2009/05/testing-private-methods-with-c-40.html )
I am aware that I can use reflection to get generic type parameters here, but I'm looking for a nicer solution - if there is one.

The fastest equivalent I can guess:
private static readonly Func<InvokeMemberBinder, IList<Type>> GetTypeArguments;
static TransparentObject()
{
var type = typeof(RuntimeBinderException).Assembly.GetTypes().Where(x => x.FullName == "Microsoft.CSharp.RuntimeBinder.CSharpInvokeMemberBinder").Single();
var dynamicMethod = new DynamicMethod("#", typeof(IList<Type>), new[] { typeof(InvokeMemberBinder) }, true);
var il = dynamicMethod.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Castclass, type);
il.Emit(OpCodes.Call, type.GetProperty("Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder.TypeArguments", BindingFlags.Instance | BindingFlags.NonPublic).GetGetMethod(true));
il.Emit(OpCodes.Ret);
GetTypeArguments = (Func<InvokeMemberBinder, IList<Type>>)dynamicMethod.CreateDelegate(typeof(Func<InvokeMemberBinder, IList<Type>>));
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
var method = typeof(T).GetMethod(binder.Name, BindingFlags.Public| BindingFlags.NonPublic | BindingFlags.Instance);
if (method == null) throw new MissingMemberException(string.Format("Method '{0}' not found for type '{1}'", binder.Name, typeof(T)));
var typeArguments = GetTypeArguments(binder);
if (typeArguments.Count > 0) method = method.MakeGenericMethod(typeArguments.ToArray());
result = method.Invoke(target, args);
return true;
}

Related

How to use reflection to get a method with a ref keyword?

Yeah so I set up a little TestClass to figure out what GetMethod would work to actually find the method Test(ref int i). But so far nothing worked.
[Button(nameof(Method))]
public bool whatever;
private void Test(ref int i)
{
Debug.Log("Works");
}
private void Method()
{
Type[] types = { typeof(int) };
MethodInfo methodInfo = GetType().GetMethod(nameof(Test),
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static,
null, types, null);
Debug.Log(methodInfo);
}
What am I supposed to do? I couldn't find anything on the web so far (for GetMethod specifically)
If you mix Eser + gcores you obtain:
private void Test(ref int i)
{
Console.WriteLine(i);
i++;
}
private void Test2(out int i)
{
i = 1000;
}
public void Method()
{
Type[] types = { typeof(int).MakeByRefType() };
MethodInfo methodInfo = GetType().GetMethod(nameof(Test), BindingFlags.NonPublic | BindingFlags.Instance, null, types, null);
int num = 10;
var pars = new object[] { num };
methodInfo.Invoke(this, pars);
Console.WriteLine(pars[0]);
MethodInfo methodInfo2 = GetType().GetMethod(nameof(Test2), BindingFlags.NonPublic | BindingFlags.Instance, null, types, null);
var pars2 = new object[1];
methodInfo2.Invoke(this, pars2);
Console.WriteLine(pars2[0]);
}
Note the typeof(int).MakeByRefType(), and the fact that the object[] array containing the parameters is modified by the invoked method. I've added a second example with out that shows that you still use .MakeByRefType(), only you don't need to initialize the object[] array with a parameter. Ah and you should use the exact BindingFlags you need, not throw every BindingFlags contained in MSDN together. Static and non-static work differently :-)
You can find the method with specified arguments' types by calling an appropriate overload of GetMethod. To make the parameter a reference type use the code:
Type[] types = { typeof(int).MakeByRefType() };

ILGenerator Emit : Load propertyInfo has method parameter

I'm trying to make this code in IL using ILGenerator.Emit
class Foo
{
...
}
public class TestClass
{
public static void test()
{
Type t = typeof(Foo);
foreach(PropertyInfo p in t.GetProperties())
{
GenerateVar(p.PropertyInfo);
}
}
public static object GenerateVar(Type var)
{
if (var == typeof(Int32))
{
return 5;
}
else if (var == typeof(Char))
{
return 'a';
}
return null;
}
}
This is what I've done so far, and had some complications:
MethodInfo mi = TestClass.GetType().GetMethod("GenerateVar",
BindingFlags.Public |
BindingFlags.Instance);
ILGenerator generator = mb.GetILGenerator();
LocalBuilder propertyType;
LocalBuilder TestClass = mb_gen.DeclareLocal(typeof(TestClass));
foreach (PropertyInfo pi in t.GetProperties())
{
propertyType = mb_gen.DeclareLocal(pi.PropertyType);
//loads into the stack the current PropertyType and the method class
generator.Emit(OpCodes.Ldloc, TestClass);
generator.Emit(OpCodes.LdLoc, propertyType);
//calls GenerateVar(Type var) to get a PropertyType var
generator.Emit(OpCodes.Callvirt, mi);
}
It gives me the following exception:
-> expected type: System.Type , Received type: System.String
System.String is the property type that was given by: pi.PropertyType;
What am I doing wrong?
Thanks in advance
As thehennyy comment, if you can give us the full code we will can to help better. I'm trying to help here because I guess what you try to do.
So I based here on your C# code. As I understand you want to create a method that get properties of type (Foo in your case) and foreach of them, get some value based on type.
Here is a snippet of doing it for first property of the type. To complete the code you need to emit the loop, or, like you wrote in your question, loop on the properties in your C# code and emit the code for each property one after one.
static void CallGenerateVar()
{
var dm = new DynamicMethod("CallGenerateVar", typeof(object), Type.EmptyTypes, typeof(TestClass));
MethodInfo generateVarMethod = typeof(TestClass).GetMethod("GenerateVar", BindingFlags.Public | BindingFlags.Instance);
var ilGen = dm.GetILGenerator();
var properties = ilGen.DeclareLocal(typeof(PropertyInfo[]));
var index = ilGen.DeclareLocal(typeof(int));
var propInfo = ilGen.DeclareLocal(typeof(PropertyInfo));
ilGen.Emit(System.Reflection.Emit.OpCodes.Ldtoken, typeof(Foo));
ilGen.Emit(System.Reflection.Emit.OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", BindingFlags.Static | BindingFlags.Public));
ilGen.Emit(System.Reflection.Emit.OpCodes.Callvirt, typeof(Type).GetMethod("GetProperties", Type.EmptyTypes));
ilGen.Emit(System.Reflection.Emit.OpCodes.Stloc_0);
ilGen.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0);
ilGen.Emit(System.Reflection.Emit.OpCodes.Stloc_1);
ilGen.Emit(System.Reflection.Emit.OpCodes.Ldloc_0);
ilGen.Emit(System.Reflection.Emit.OpCodes.Ldloc_1);
ilGen.Emit(System.Reflection.Emit.OpCodes.Ldelem_Ref);
ilGen.Emit(System.Reflection.Emit.OpCodes.Stloc_2);
ilGen.Emit(System.Reflection.Emit.OpCodes.Ldloc_0);
ilGen.Emit(System.Reflection.Emit.OpCodes.Ldloc_2);
ilGen.Emit(System.Reflection.Emit.OpCodes.Callvirt, typeof(PropertyInfo).GetMethod("get_PropertyType", BindingFlags.Instance | BindingFlags.Public));
ilGen.Emit(System.Reflection.Emit.OpCodes.Callvirt, generateVarMethod);
ilGen.Emit(System.Reflection.Emit.OpCodes.Ret);
var del = (Func<object>)dm.CreateDelegate(typeof(Func<object>));
var result = del.Invoke();
}
In case our Foo type looks like this:
class Foo
{
public int MyProperty { get; set; }
}
And GenerateVar looks like this:
public object GenerateVar(Type var)
{
if (var == typeof(Int32))
{
return 5;
}
else if (var == typeof(Char))
{
return 'a';
}
return null;
}
It will print 5

Why does it return null when I try to invoke generic methods?

I've been trying to execute generic methods and using recursion. The problem is that the method GetMethod returns null. How can I improve the code?
public static T GetElementObject<T>(this XElement element)
{
T returnObject = Activator.CreateInstance<T>();
PropertyInfo[] propertyInfos = returnObject.GetType().GetProperties();
Type propertyType;
foreach (PropertyInfo propertyInfo in propertyInfos)
{
propertyType = propertyInfo.PropertyType;
if (propertyType.IsAssignableFrom(typeof(BaseProxyEntity)))
{
MethodInfo getElementObject = typeof(Utility).GetMethod("GetElementObject<>", System.Reflection.BindingFlags.Static | BindingFlags.Public).MakeGenericMethod(propertyType);
propertyInfo.SetValue(returnObject, getElementObject.Invoke(null, new object[] { element.Descendants(propertyInfo.Name) }), null);
}
else if (propertyType.IsValueType == true)
{
MethodInfo CastValue = typeof(Utility).GetMethod("CastValue<>", System.Reflection.BindingFlags.Static | BindingFlags.Public).MakeGenericMethod(propertyType);
propertyInfo.SetValue(returnObject, CastValue.Invoke(null, new object[] { element.Attribute(propertyInfo.Name).Value }), null);
}
//Other else conditions ...
}
return returnObject;
}
While Eugen Rieck is correct that names are mangled for generic types, they are not mangled for generic methods. Try without the angle brackets: GetMethod("GetElementObject", ... and GetMethod("CastValue",
GetMethod("GetElementObject<>", ...)
Will allways return null, as there is no such method. Names are mangled for generic types, start with listing all methods and proceed from there.

WP7: Type.GetMethods throws MethodAccessException. Is there a workaround for this bug?

I try to get a list of all methods of a type. Type provides the GetMethods method to do this. But unfortunately it seems to be incorrectly implemented. It works properly as long as there is no overridden generic method on the reflected type. In this special case a MethodAccessException is thrown.
Does anyone have a workaround for this WP7 bug? I'm fine if all methods except the generic ones are returned.
Here is a sample of a class that will throw an exception. Note: the none generic return value is intended to prove that the return value is not involved in the problem. Furthermore, the base method can be changed to abstract and the problem still remains.
public abstract class BaseClassWithGenericMethod
{
public virtual System.Collections.IList CreateList<T>()
{
return new List<T>();
}
}
public class DerivedClassWithGenericMethod
: BaseClassWithGenericMethod
{
public override System.Collections.IList CreateList<T>()
{
return new List<T>();
}
}
I'd grab them all (note the BindingFlags.DeclaredOnly in GetMethods) and then filter out those that are generic methods (MethodInfo.IsGenericMethod).
Sorry for the VB, I know the whole world wants C# these days, but...
Public Function GetListOfMethods() As List(Of MethodInfo)
Dim d As New DerivedClassWithGenericMethod
Dim myArrayMethodInfo() As Reflection.MethodInfo
myArrayMethodInfo = d.GetType.GetMethods(BindingFlags.Instance _
Or BindingFlags.Public _
Or BindingFlags.DeclaredOnly)
Dim myArrayMethodInfoList As New List(Of MethodInfo)
For Each m As MethodInfo In myArrayMethodInfo
If Not m.IsGenericMethod Then
myArrayMethodInfoList.Add(m)
End If
Next
Return myArrayMethodInfoList
End Function
I just tested on WP7 using your sample classes and it works fine.
Finally I got it working. The following Type extension methods return exactly the same result as the .NET 4.0 implementation but without the MethodAccess exceptions thrown by WP7:
public static class TypeExtensions
{
public static MethodInfo GetMethodWp7Workaround(this Type type, string name)
{
if (name == null)
{
throw new ArgumentNullException("name");
}
return GetMethod(type, name, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance, null, CallingConventions.Any, null, null);
}
public static MethodInfo GetMethodWp7Workaround(this Type type, string name, Type[] types)
{
if (name == null)
{
throw new ArgumentNullException("name");
}
if (types == null)
{
throw new ArgumentNullException("types");
}
if (types.Any(t => t == null))
{
throw new ArgumentNullException("types");
}
return GetMethod(type, name, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance, null, CallingConventions.Any, types, null);
}
public static MethodInfo GetMethodWp7Workaround(this Type type, string name, BindingFlags bindingAttr)
{
if (name == null)
{
throw new ArgumentNullException("name");
}
return GetMethod(type, name, bindingAttr, null, CallingConventions.Any, null, null);
}
public static MethodInfo GetMethodWp7Workaround(this Type type, string name, Type[] types, ParameterModifier[] modifiers)
{
if (name == null)
{
throw new ArgumentNullException("name");
}
if (types == null)
{
throw new ArgumentNullException("types");
}
if (types.Any(t => t == null))
{
throw new ArgumentNullException("types");
}
return GetMethod(type, name, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance, null, CallingConventions.Any, types, modifiers);
}
public static MethodInfo GetMethodWp7Workaround(this Type type, string name, BindingFlags bindingAttr, Binder binder, Type[] types, ParameterModifier[] modifiers)
{
if (name == null)
{
throw new ArgumentNullException("name");
}
if (types == null)
{
throw new ArgumentNullException("types");
}
if (types.Any(t => t == null))
{
throw new ArgumentNullException("types");
}
return GetMethod(type, name, bindingAttr, binder, CallingConventions.Any, types, modifiers);
}
public static MethodInfo GetMethodWp7Workaround(this Type type, string name, BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers)
{
if (name == null)
{
throw new ArgumentNullException("name");
}
if (types == null)
{
throw new ArgumentNullException("types");
}
if (types.Any(t => t == null))
{
throw new ArgumentNullException("types");
}
return GetMethod(type, name, bindingAttr, binder, callConvention, types, modifiers);
}
private static MethodInfo GetMethod(
Type type,
string name,
BindingFlags bindingFlags,
Binder binder,
CallingConventions callConvention,
Type[] types,
ParameterModifier[] modifiers)
{
if ((bindingFlags & BindingFlags.DeclaredOnly) == BindingFlags.DeclaredOnly)
{
return types == null
? type.GetMethod(name, bindingFlags)
: type.GetMethod(name, bindingFlags, binder, callConvention, types, modifiers);
}
bool isBaseType = false;
bindingFlags = bindingFlags | BindingFlags.DeclaredOnly;
MethodInfo result = null;
while (result == null && type != null)
{
result =
types == null
? type.GetMethod(name, bindingFlags)
: type.GetMethod(name, bindingFlags, binder, callConvention, types, modifiers);
if (isBaseType && result != null && result.IsPrivate)
{
result = null;
}
type = type.BaseType;
if (!isBaseType)
{
isBaseType = true;
bindingFlags = bindingFlags & (~BindingFlags.Static);
}
}
return result;
}
public static MethodInfo[] GetMethodsWp7Workaround(this Type type)
{
return type.GetMethodsWp7Workaround(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance);
}
public static MethodInfo[] GetMethodsWp7Workaround(this Type type, BindingFlags flags)
{
if ((flags & BindingFlags.DeclaredOnly) == BindingFlags.DeclaredOnly)
{
return type.GetMethods(flags);
}
flags = flags | BindingFlags.DeclaredOnly;
Type currentType = type;
bool isBaseType = false;
var methods = new List<MethodInfo>();
while (currentType != null)
{
var newMethods = currentType.GetMethods(flags).Where(m => ShouldBeReturned(m, methods, isBaseType));
methods.AddRange(newMethods);
currentType = currentType.BaseType;
if (!isBaseType)
{
isBaseType = true;
flags = flags & (~BindingFlags.Static);
}
}
return methods.ToArray();
}
private static bool ShouldBeReturned(
MethodInfo method,
IEnumerable<MethodInfo> foundMethods,
bool isCurrentTypeBaseType)
{
return !isCurrentTypeBaseType || (!method.IsPrivate && !HasAlreadyBeenFound(method, foundMethods));
}
private static bool HasAlreadyBeenFound(
MethodInfo method,
IEnumerable<MethodInfo> processedMethods)
{
if (!method.IsGenericMethodDefinition)
{
return processedMethods.Any(m => m.GetBaseDefinition().Equals(method.GetBaseDefinition()));
}
return processedMethods.Any(
m => m.Name == method.Name &&
HaveSameGenericArguments(m, method) &&
HaveSameParameters(m, method));
}
private static bool HaveSameParameters(MethodInfo method1, MethodInfo method2)
{
var parameters1 = method1.GetParameters();
var parameters2 = method2.GetParameters();
return parameters1.Length == parameters2.Length &&
parameters1.All(parameters2.Contains);
}
private static bool HaveSameGenericArguments(MethodInfo method1, MethodInfo method2)
{
var genericArguments1 = method1.GetGenericArguments();
var genericArguments2 = method2.GetGenericArguments();
return genericArguments1.Length == genericArguments2.Length;
}
}
You will get the same result for the following class with .NET 4.0 and this workaround on WP7:
internal class TestBaseClass
{
private static void BasePrivateStaticMethod() { }
private void BasePrivateMethod() { }
private void BasePrivateGenericMethod<T>() { }
protected static void BaseProtectedStaticMethod() { }
protected void BaseProtectedMethod() { }
protected void BaseProtectedGenericMethod<T>() { }
protected virtual void OverriddenProtectedMethod() { }
protected virtual void OverriddenProtectedGenericMethod<T>() { }
internal static void BaseInternalStaticMethod() { }
internal void BaseInternalMethod() { }
internal void BaseInternalGenericMethod<T>() { }
internal virtual void OverriddenInternalMethod() { }
internal virtual void OverriddenInternalGenericMethod<T>() { }
public static void BasePublicStaticMethod() { }
public void BasePublicMethod() { }
public void BasePublicGenericMethod<T>() { }
public virtual void OverriddenPublicMethod() { }
public virtual void OverriddenPublicGenericMethod<T>() { }
}
internal class TestClass : TestBaseClass
{
public string Property
{
get { return null; }
}
private static void PrivateStaticMethod() { }
private void PrivateMethod() { }
private void PrivateGenericMethod<T>() { }
protected static void ProtectedStaticMethod() { }
protected void ProtectedMethod() { }
protected static void ProtectedGenericMethod<T>() { }
internal static void InternalGenericMethod<T>() { }
internal void InternalMethod() { }
internal static void InternalStaticMethod() { }
public static void PublicStaticMethod() { }
public void PublicMethod() { }
public static void PublicGenericMethod<T>() { }
internal override void OverriddenInternalMethod()
{
base.OverriddenInternalMethod();
}
protected override void OverriddenProtectedMethod()
{
base.OverriddenProtectedMethod();
}
public override void OverriddenPublicMethod()
{
base.OverriddenPublicMethod();
}
internal override void OverriddenInternalGenericMethod<T>()
{
base.OverriddenInternalGenericMethod<T>();
}
protected override void OverriddenProtectedGenericMethod<T>()
{
base.OverriddenProtectedGenericMethod<T>();
}
public override void OverriddenPublicGenericMethod<T>()
{
base.OverriddenPublicGenericMethod<T>();
}
}
Could you actually be misinterpreting the behavior you are seeing? I am thinking you are experiencing a valid security access issue and nothing to do with the implementation of reflection on WP7 (other than its security model).
Look at this post. Could the type you are reflecting, any of the methods in question or the Type assigned to T in your particular case be marked as security critical with the SecurityCriticalAttribute?
I gotta admit that I doubted what you are reporting but it is indeed easily reproducible and does look like a bug to me. I think you should report it on Microsoft connect.
As for work arounds...
This will get you the members of the derived class and then the base class (including the generic) without error:
var m = new DerivedClassWithGenericMethod();
foreach (var method in m.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly))
Debug.WriteLine(method.Name);
foreach (var method in m.GetType().BaseType.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly))
Debug.WriteLine(method.Name);
This can be generalized (quick and dirty implementation) somewhat like so (The EqualityComprarer should filter out base class members that are overriden or hidden by derived classes):
class MethodComparer : IEqualityComparer<MethodInfo>
{
public bool Equals(MethodInfo x, MethodInfo y)
{
return GetHashCode(x) == GetHashCode(y);
}
public int GetHashCode(MethodInfo obj)
{
int hash = obj.Name.GetHashCode();
foreach (var param in obj.GetParameters())
hash ^= param.ParameterType.GetHashCode();
if (obj.IsGenericMethodDefinition)
{
hash ^= obj.GetGenericArguments().Length.GetHashCode();
}
else if (obj.IsGenericMethod)
{
foreach (var t in obj.GetGenericArguments())
hash ^= t.GetHashCode();
}
return hash;
}
}
static class Ext
{
public static MethodInfo[] MyGetMethods(this Type t)
{
if (t == null)
return new MethodInfo[] { };
var methods = t.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
var baseMethods = from m in t.BaseType.MyGetMethods()
where !methods.Contains(m, new MethodComparer())
select m;
return methods.Concat(baseMethods).ToArray();
}
}
var m = new DerivedClassWithGenericMethod();
foreach (var method in m.GetType().MyGetMethods())
Debug.WriteLine(method.Name);
Theres a GetMethods(BindingFlags). Try filtering out the methods you are getting with the BindingFlags argument.

Reflection GetMethod. select a more specific method

i want to get the method but there are more then one overload. For example in object i tried to get 'Equals'. When using
public virtual bool Equals(object obj);
public static bool Equals(object objA, object objB);
writing typeof(Object).GetMethod("Equals") got me an exception, writing typeof(Object).GetMethod("public virtual bool Equals(object obj)") got me null. How do i specify which method i want in this case?
Use one of the overloads that lets you specify the parameter types.
For example:
var staticMethod = typeof(Object).GetMethod("Equals",
BindingFlags.Static | BindingFlags.Public,
null,
new Type[] { typeof(object), typeof(object) },
null);
var instanceMethod = typeof(Object).GetMethod("Equals",
BindingFlags.Instance | BindingFlags.Public,
null,
new Type[] { typeof(object) },
null);
Or alternatively:
var staticMethod = typeof(Object).GetMethod("Equals",
new Type[] { typeof(object), typeof(object) });
var instanceMethod = typeof(Object).GetMethod("Equals",
new Type[] { typeof(object) });
MethodInfo methodInfo = typeof(object).GetMethod("Equals", new Type[] { typeof(object), typeof(object) });
You can try this code..
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
var actionName = filterContext.RouteData.Values["action"].ToString();
var ctlr = filterContext.Controller as Controller;
if (ctlr == null) return;
var invoker = ctlr.ActionInvoker as ControllerActionInvoker;
if (invoker == null) return;
var invokerType = invoker.GetType();
var getCtlrDescMethod = invokerType.GetMethod("GetControllerDescriptor", BindingFlags.NonPublic | BindingFlags.Instance);
var ctlrDesc = getCtlrDescMethod.Invoke(invoker, new object[] {ctlr.ControllerContext}) as ControllerDescriptor;
var findActionMethod = invokerType.GetMethod("FindAction", BindingFlags.NonPublic | BindingFlags.Instance);
var actionDesc = findActionMethod.Invoke(invoker, new object[] { ctlr.ControllerContext, ctlrDesc, actionName }) as ReflectedActionDescriptor;
if (actionDesc == null) return;
if (actionDesc.MethodInfo.ReturnType == typeof (ActionResult))
{
// you're in
}
}

Categories