How do I invoke an extension method using reflection?
Solution 1
As others said, extensions methods are compiler magic, you can alway use VS right click, go to definition to find the real type that implements the static method.
From there, it gets fairly hairy. Where
is overloaded, so you need to find the actual definition that matches the signature you want. GetMethod
has some limitations with generic types so you have to find the actual one using a search.
Once you find the method, you must make the MethodInfo
specific using the MakeGenericMethod
call.
Here is a full working sample:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
namespace ConsoleApplication9 {
class Program {
class MyObject {
public string Name { get; set; }
}
public static void CallWhereMethod() {
List<MyObject> myObjects = new List<MyObject>() {
new MyObject { Name = "Jon Simpson" },
new MyObject { Name = "Jeff Atwood" }
};
Func<MyObject, bool> NameEquals = BuildEqFuncFor<MyObject>("Name", "Jon Simpson");
// The Where method lives on the Enumerable type in System.Linq
var whereMethods = typeof(System.Linq.Enumerable)
.GetMethods(BindingFlags.Static | BindingFlags.Public)
.Where(mi => mi.Name == "Where");
Console.WriteLine(whereMethods.Count());
// 2 (There are 2 methods that are called Where)
MethodInfo whereMethod = null;
foreach (var methodInfo in whereMethods) {
var paramType = methodInfo.GetParameters()[1].ParameterType;
if (paramType.GetGenericArguments().Count() == 2) {
// we are looking for Func<TSource, bool>, the other has 3
whereMethod = methodInfo;
}
}
// we need to specialize it
whereMethod = whereMethod.MakeGenericMethod(typeof(MyObject));
var ret = whereMethod.Invoke(myObjects, new object[] { myObjects, NameEquals }) as IEnumerable<MyObject>;
foreach (var item in ret) {
Console.WriteLine(item.Name);
}
// outputs "Jon Simpson"
}
public static Func<T, bool> BuildEqFuncFor<T>(string prop, object val) {
return t => t.GetType().InvokeMember(prop, BindingFlags.GetProperty,
null, t, null) == val;
}
static void Main(string[] args) {
CallWhereMethod();
Console.ReadKey();
}
}
}
Solution 2
Extension methods are really just static methods underwater. An extension method call like foo.Frob(arguments) is really just SomeClass.Frob(foo, arguments). In the case of the Where method, you're looking for System.Linq.Enumerable.Where. So get the typeof Enumerable and invoke Where on that.
Solution 3
I'm a bit off and late but this could help you if you need to call Linq extensions of a IEnumerable wich type is unkown.
IEnumerable<dynamic> test = obj as IEnumerable<dynamic>;
then maybe test obj if not null and
int count = test.Count()
for me that worked very well.
Solution 4
Here's an answer for a general case where the method name is unique (so not in the same case the original posted asked, because Enumerable.Where is overloaded).
Say you have a target object targetObject
of the type which is extended, where the extension method is defined in a class TargetClassExtensions
and whose extension method's name is ExtensionMethod
which takes in an integer parameter and is generic for which you want to call for the class TargetGenericClass
.
Then, to call this extension method through reflection, do the following:
int inputInteger = 9; // Example input for the generic method.
object? result = typeof(TargetClassExtensions)
.GetMethod(nameof(TargetClassExtensions.ExtensionMethod))
.MakeGenericMethod(typeof(TargetGenericClass))
.Invoke(null, new object[] { targetObject, inputInteger });
Comments
-
Faisal Ansari almost 4 years
I appreciate that similar questions have been asked before, but I am struggling to invoke the Linq Where method in the following code. I am looking to use reflection to dynamically call this method and also dynamically build the delegate (or lambda) used in the Where clause. This is a short code sample that, once working, will help to form part of an interpreted DSL that I am building. Cheers.
public static void CallWhereMethod() { List<MyObject> myObjects = new List<MyObject>(){new MyObject{Name="Jon Simpson"}}; System.Delegate NameEquals = BuildEqFuncFor<MyObject>("Name", "Jon Simpson"); object[] atts = new object[1] ; atts[0] = NameEquals; var ret = typeof(List<MyObject>).InvokeMember("Where", BindingFlags.InvokeMethod, null, InstanceList,atts); } public static Func<T, bool> BuildEqFuncFor<T>(string prop, object val) { return t => t.GetType().InvokeMember(prop,BindingFlags.GetProperty, null,t,null) == val; }
-
Steven Sudit over 14 yearsThey're a .NET trick, not a C# one. VB.NET can make and use them, too, though the syntax is different, and involves attributes.
-
Faisal Ansari over 14 yearsI get a MissingMethodException using var ret = typeof(System.Linq.Enumerable).InvokeMember("Where", BindingFlags.InvokeMethod, null, InstanceList, atts); Any ideas? Thanks.
-
Joren over 14 yearsThe problem is that the method is generic. I found a pretty good blog post on invoking generic methods (blogs.microsoft.co.il/blogs/gilf/archive/2008/10/10/…), but there is one additional problem: There are two overloads of Enumerable.Where, differing only in the type on one of the parameters (Func<T, bool> versus Func<T, int, bool>) and I haven't found out yet how to neatly select the one you want.
-
Faisal Ansari over 14 yearsThanks for putting the effort into this. Much appreciated.
-
Joren over 14 yearsI suppose then that there is no direct way to have the framework select the appropriate method? That was what I was looking for, but wasn't able to find anything. +1 For working it out.
-
ICR over 14 yearsThey're still a compiler trick, it's just the VB.NET compiler also uses the same trick.
-
Preet Sangha over 14 yearsI love the irony of using the where method to find the where method :-)
-
Faisal Ansari over 11 yearsThanks for this, dynamic was a game changer and I have since changed my entire approach!