Getting hold of the MethodInfo of a generic method via Reflection (so you can invoke it dynamically, for example) can be a bit of a pain. So this afternoon I formulated a pain-killer, SymbolExtensions.GetMethodInfo. It’s not fussy: it works for non-generic methods too. You use it like this:
internal class SymbolExtensionsTests
{
[Test]
public void GetMethodInfo_should_return_method_info()
{
var methodInfo = SymbolExtensions.GetMethodInfo<TestClass>(c => c.AMethod());
methodInfo.Name.ShouldEqual("AMethod");
}
[Test]
public void GetMethodInfo_should_return_method_info_for_generic_method()
{
var methodInfo = SymbolExtensions.GetMethodInfo<TestClass>(c => c.AGenericMethod(default(int)));
methodInfo.Name.ShouldEqual("AGenericMethod");
methodInfo.GetParameters().First().ParameterType.ShouldEqual(typeof(int));
}
[Test]
public void GetMethodInfo_should_return_method_info_for_static_method_on_static_class()
{
var methodInfo = SymbolExtensions.GetMethodInfo(() => StaticTestClass.StaticTestMethod());
methodInfo.Name.ShouldEqual("StaticTestMethod");
methodInfo.IsStatic.ShouldBeTrue();
}
}
The active ingredient, as you can see, is Lambda expressions:
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System;
public static class SymbolExtensions
{
/// <summary>
/// Given a lambda expression that calls a method, returns the method info.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="expression">The expression.</param>
/// <returns></returns>
public static MethodInfo GetMethodInfo(Expression<Action> expression)
{
return GetMethodInfo((LambdaExpression)expression);
}
/// <summary>
/// Given a lambda expression that calls a method, returns the method info.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="expression">The expression.</param>
/// <returns></returns>
public static MethodInfo GetMethodInfo<T>(Expression<Action<T>> expression)
{
return GetMethodInfo((LambdaExpression)expression);
}
/// <summary>
/// Given a lambda expression that calls a method, returns the method info.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="expression">The expression.</param>
/// <returns></returns>
public static MethodInfo GetMethodInfo<T, TResult>(Expression<Func<T, TResult>> expression)
{
return GetMethodInfo((LambdaExpression)expression);
}
/// <summary>
/// Given a lambda expression that calls a method, returns the method info.
/// </summary>
/// <param name="expression">The expression.</param>
/// <returns></returns>
public static MethodInfo GetMethodInfo(LambdaExpression expression)
{
MethodCallExpression outermostExpression = expression.Body as MethodCallExpression;
if (outermostExpression == null)
{
throw new ArgumentException("Invalid Expression. Expression should consist of a Method call only.");
}
return outermostExpression.Method;
}
}


5 comments:
Yeah this is a fun idea that I've seen independently pop up in several places.
Daniel Cazzulino publically posted some code around this at http://www.clariusconsulting.net/blogs/kzu/archive/2006/07/06/TypedReflection.aspx a while back and in the internal code sites at MS my team had written a similar library. Nice to see the power of expressions getting recognized.
-cheers
Thank for this info. I have a question: the following test:
[Test]
public void GetMethodInfo_should_return_method_info_returning_functions() { var methodInfo = SymbolExtensions.GetMethodInfo>(c => c.AMethod); methodInfo.Name.ShouldEqual("AMethod"); }
Didn't work
Darien, I think Disqus formatting destroyed your code. Do you want to send me an email instead, and I'll see what I can figure out?
I've found this really useful in many places. Thanks a lot for the post.
This is an incredibly useful tool for working with reflection.
Post a Comment