Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用反射调用扩展方法?_C#_Linq_Reflection_Delegates_Lambda - Fatal编程技术网

C# 如何使用反射调用扩展方法?

C# 如何使用反射调用扩展方法?,c#,linq,reflection,delegates,lambda,C#,Linq,Reflection,Delegates,Lambda,我很感激以前有人问过类似的问题,但我很难在下面的代码中调用LinqWhere方法。我希望使用反射动态调用此方法,并动态构建Where子句中使用的委托(或lambda)。这是一个简短的代码示例,一旦工作,将有助于形成我正在构建的解释DSL的一部分。干杯 public static void CallWhereMethod() { List<MyObject> myObjects = new List<MyObject>(){new MyObj

我很感激以前有人问过类似的问题,但我很难在下面的代码中调用LinqWhere方法。我希望使用反射动态调用此方法,并动态构建Where子句中使用的委托(或lambda)。这是一个简短的代码示例,一旦工作,将有助于形成我正在构建的解释DSL的一部分。干杯

    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;
    }
公共静态void CallWhereMethod()
{
List myObjects=new List(){new MyObject{Name=“Jon Simpson”};
System.Delegate namequals=BuildEqFuncFor(“Name”,“Jon Simpson”);
object[]atts=新对象[1];
atts[0]=名称等于;
var ret=typeof(List).InvokeMember(“Where”,BindingFlags.InvokeMethod,null,InstanceList,atts);
}
公共静态函数BuildEqFuncFor(字符串属性,对象值)
{
返回t=>t.GetType().InvokeMember(prop,BindingFlags.GetProperty,
null,t,null)=val;
}

扩展方法是一种c#编译器技巧,它们在相关类型中不存在。它们(这些特定的)存在于System.Linq名称空间中的静态类中。我建议在reflector中反映这一点,然后调用这些类型的反射

扩展方法实际上只是水下的静态方法。像foo.Frob(arguments)这样的扩展方法调用实际上只是SomeClass.Frob(foo,arguments)。对于Where方法,您要查找System.Linq.Enumerable.Where。因此,获取Enumerable的类型并调用其中的Where。

您的代码示例有点混乱。。。除非MyObject是可枚举的


使用反射,您必须调用System.Linq.Enumerable上的Where,传入要在Where on上执行的枚举

正如其他人所说,扩展方法是编译器的魔法,您可以始终使用VS右键单击,转到定义以查找实现静态方法的实际类型

从那里,它变得相当多毛
其中
重载,因此需要找到与所需签名匹配的实际定义
GetMethod
对泛型类型有一些限制,因此您必须使用搜索来查找实际类型

找到方法后,必须使用
MakeGenericMethod
调用使
MethodInfo
特定

以下是完整的工作示例:

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();

        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
运用系统反思;
命名空间控制台应用程序9{
班级计划{
类MyObject{
公共字符串名称{get;set;}
} 
公共静态void CallWhereMethod(){
List myObjects=new List(){
新MyObject{Name=“Jon Simpson”},
新MyObject{Name=“Jeff Atwood”}
};
Func namequals=BuildEqFuncFor(“名称”、“乔恩·辛普森”);
//Where方法位于System.Linq中的可枚举类型上
var whereMethods=typeof(System.Linq.Enumerable)
.GetMethods(BindingFlags.Static | BindingFlags.Public)
.Where(mi=>mi.Name==“Where”);
Console.WriteLine(whereMethods.Count());
//2(有两个方法在何处调用)
MethodInfo,其中method=null;
foreach(var methodInfo中的whereMethods){
var paramType=methodInfo.GetParameters()[1].ParameterType;
if(paramType.GetGenericArguments().Count()==2){
//我们在找Func,另一个有3个
其中method=methodInfo;
}
}
//我们需要专门化它
whereMethod=whereMethod.MakeGenericMethod(typeof(MyObject));
var ret=whereMethod.Invoke(myObjects,new object[]{myObjects,namequals})作为IEnumerable;
foreach(ret中的var项目){
Console.WriteLine(项目名称);
}
//输出“乔恩·辛普森”
}
公共静态函数BuildEqFuncFor(字符串属性,对象值){
返回t=>t.GetType().InvokeMember(prop,BindingFlags.GetProperty,
null,t,null)=val;
}
静态void Main(字符串[]参数){
callwhere方法();
Console.ReadKey();
}
}
}

我有点晚了,但如果您需要调用IEnumerable类型未知的Linq扩展,这可能会对您有所帮助

IEnumerable测试=对象为IEnumerable

如果不为空,则可能测试obj,并且

int count=test.count()


对我来说,这很有效

这里是一个一般情况下的答案,其中方法名是唯一的(因此与原始发布的问题不同,因为Enumerable.where是重载的)

假设您有一个扩展类型的目标对象
targetObject
,其中,扩展方法是在类
TargetClassExtensions
中定义的,其扩展方法的名称是
ExtensionMethod
,它接受一个整数参数,并且是要为类
TargetGenericClass
调用的泛型

然后,要通过反射调用此扩展方法,请执行以下操作:

int-inputInteger=9;//泛型方法的示例输入。
对象结果=类型(TargetClassExtensions)
.GetMethod(名称(TargetClassExtensions.ExtensionMethod))
.MakeGenericMethod(typeof(TargetGenericClass))
.Invoke(null,新对象[]{targetObject,inputInteger});

它们是.NET的把戏,而不是C#one。VB.NET也可以制作和使用它们,尽管语法不同,并且涉及属性。它们仍然是一个编译器技巧,只是VB.NET编译器也使用相同的技巧。很好,