Can you get Func <T> (or the like) from a MethodInfo object?
I understand that, generally speaking, there are consequences of using reflection. (I myself am not a fan of thinking at all, this is a purely academic question.)
Suppose there is some class that looks like this:
public class MyClass { public string GetName() { return "My Name"; } } The bear is with me here. I know that if I have an instance of MyClass called x , I can call x.GetName() . Alternatively, I could set the variable Func<string> to x.GetName .
Now here is my question. Say I donβt know that the specified class is called MyClass ; I have an object, x , but I have no idea what it is. I can check if this object has a GetName method by doing this:
MethodInfo getName = x.GetType().GetMethod("GetName"); Suppose GetName not null. Then I could not also check if getName.ReturnType == typeof(string) and getName.GetParameters().Length == 0 , and at this point I am not sure that the method represented by my GetName object can definitely be dropped in Func<string> , somehow?
I understand MethodInfo.Invoke there, and I also understand that I could always create a Func<string> like:
Func<string> getNameFunc = () => getName.Invoke(x, null); I suggest that I ask if there is a way to move an object from a MethodInfo to the actual method that it represents, resulting in the cost of performing the reflection in the process, but after this point you can call the method directly (via, for example, Func<string> or something like that) without a penalty for performance.
What I present might look something like this:
// obviously this would throw an exception if GetActualInstanceMethod returned // something that couldn't be cast to a Func<string> Func<string> getNameFunc = (Func<string>)getName.GetActualInstanceMethod(x); (I understand that this does not exist, I wonder if there is anything like that.)
This view replaces my previous answer because it, although a slightly long route, gives you a quick method call and, unlike some other answers, allows you to go through different instances (in case you are going to encounter multiple instances of the same type). If you don't want this, check out my update below (or look at Ben M's answer).
Here is a test method that does what you want:
public class TestType { public string GetName() { return "hello world!"; } } [TestMethod] public void TestMethod2() { object o = new TestType(); var input = Expression.Parameter(typeof(object), "input"); var method = o.GetType().GetMethod("GetName", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public); //you should check for null *and* make sure the return type is string here. Assert.IsFalse(method == null && !method.ReturnType.Equals(typeof(string))); //now build a dynamic bit of code that does this: //(object o) => ((TestType)o).GetName(); Func<object, string> result = Expression.Lambda<Func<object, string>>( Expression.Call(Expression.Convert(input, o.GetType()), method), input).Compile(); string str = result(o); Assert.AreEqual("hello world!", str); } Once you create a delegate once, you can cache it in the dictionary:
Dictionary<Type, Func<object, string>> _methods; All you do is add it to the dictionary using the incoming Type object (from GetType ()) as the key. In the future, you first check to see if you have a ready-made delegate in the dictionary (and call it if it is), otherwise you will create it first, add it and then call it.
By the way, this is a very simplified version of what DLR makes for it a dynamic distribution mechanism (in terms of C #, when you use the keyword "dynamic").
And finally
If, as some people have noted, you just want to bake Func directly to the object you are getting, then you will do the following:
[TestMethod] public void TestMethod3() { object o = new TestType(); var method = o.GetType().GetMethod("GetName", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public); Assert.IsFalse(method == null && !method.ReturnType.Equals(typeof(string))); //this time, we bake Expression.Constant(o) in. Func<string> result = Expression.Lambda<Func<string>>( Expression.Call(Expression.Constant(o), method)).Compile(); string str = result(); //no parameter this time. Assert.AreEqual("hello world!", str); } Please note that after the expression tree is thrown out, you must make sure that o remains in scope, otherwise you may get some unpleasant results.The easiest way is to stick with a local reference (possibly in a class instance) for the life of your delegate. (Removed as a result of Ben M comments)
Yes it is possible:
Func<string> func = (Func<string>) Delegate.CreateDelegate(typeof(Func<string>), getName); Here is my answer by building an expression tree. Unlike other answers, the result ( getNameFunc ) is a function bound to the original instance - without having to pass it as a parameter.
class Program { static void Main(string[] args) { var p = new Program(); var getNameFunc = GetStringReturningFunc(p, "GetName"); var name = getNameFunc(); Debug.Assert(name == p.GetName()); } public string GetName() { return "Bob"; } static Func<string> GetStringReturningFunc(object x, string methodName) { var methodInfo = x.GetType().GetMethod(methodName); if (methodInfo == null || methodInfo.ReturnType != typeof(string) || methodInfo.GetParameters().Length != 0) { throw new ArgumentException(); } var xRef = Expression.Constant(x); var callRef = Expression.Call(xRef, methodInfo); var lambda = (Expression<Func<string>>)Expression.Lambda(callRef); return lambda.Compile(); } } The easiest way to do this is Delegate.CreateDelegate :
Func<string> getNameFunc = (Func<string>) Delegate.CreateDelegate( typeof(Func<string>), x, getName); Note that this binds getNameFunc to x , so for each x you need to create a new delegate instance. This option is much more complicated than Expression based examples. However, with expression-based examples, you can create once Func<MyClass, string> getNameFuncForAny , which can be reused for each instance of MyClass .
To create such getNameFuncForAny, you need a method like
public Func<MyClass, string> GetInstanceMethod(MethodInfo method) { ParameterExpression x = Expression.Parameter(typeof(MyClass), "it"); return Expression.Lambda<Func<MyClass, string>>( Expression.Call(x, method), x).Compile(); } which you can use like this:
Func<MyClass, string> getNameFuncForAny = GetInstanceMethod(getName); MyClass x1 = new MyClass(); MyClass x2 = new MyClass(); string result1 = getNameFuncForAny(x1); string result2 = getNameFuncForAny(x2); If you do not want to bind to Func<MyClass, string> , you can define
public TDelegate GetParameterlessInstanceMethod<TDelegate>(MethodInfo method) { ParameterExpression x = Expression.Parameter(method.ReflectedType, "it"); return Expression.Lambda<TDelegate>( Expression.Call(x, method), x).Compile(); } You can build an Expression Tree representing the lambda that calls this method, and then Compile() so that further calls are executed as fast as standard compiled calls.
Alternatively, I wrote this method recently, based on an excellent MSDN article that generates a shell using IL to call any MethodInfo faster than with MethodInfo.DynamicInvoke , since there has been almost no overhead since generating the code for a normal call.
One of my approaches is to use dynamics. Then you could do something like this:
if( /* This method can be a Func<string> */) { dynamic methodCall = myObject; string response = methodCall.GetName(); }