RuntimeReflectionExtensions.GetRuntimeMethod无法按预期工作

时间:2014-01-23 12:14:00

标签: c# reflection portable-class-library

有没有人知道为什么在下列情况下调用GetRuntimeMethod返回null?

_toListMethod = typeof(Enumerable).GetRuntimeMethod("ToList",  new Type[] { typeof(IEnumerable<>) });

它应该像以下一样工作:

_castMethod = typeof(Enumerable).GetRuntimeMethod("Cast", new Type[] { typeof(IEnumerable) });

我尝试通过运行以下代码来调试它:

var bah = typeof (Enumerable).GetRuntimeMethods().Where(m => m.Name.Contains("ToList"));
var derp = bah.First().GetParameters();

令我惊讶的是,第一行返回一个包含我想要获取的MethodInfo的集合,第二行确认预期的参数类型是IEnumerable&lt;&gt;。

两个方法签名Cast和ToList是相似的,我看不出为什么获取ToList的MethodInfo会失败的原因。

此代码在可移植类库上运行,TargetFrameworkProfile设置为Profile78。

谢谢!

更新:在我有一个好的解决方案之前,有一个丑陋的解决方法对我有用:

_toListMethod = typeof(Enumerable).GetRuntimeMethods().First(m => m.Name.Contains("ToList"));

2 个答案:

答案 0 :(得分:4)

我查了签名,他们看起来像这样:

public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source);
public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source);

我相信可能可能是GetRunTimeMethod和使用泛型参数的扩展方法,因为这不起作用

var intToListMethod = typeof(IEnumerable<int>).GetRuntimeMethod("ToList", new Type[] { typeof(IEnumerable<int>) });

我花了一些时间并尝试为您所需的行为创建有效的扩展方法,我想出了下面的代码段。它对我有用。

public static class RuntimeMethodExtensions
{
 public static MethodInfo GetRuntimeMethodsExt(this Type type, string name, params Type[] types)
 {
  // Find potential methods with the correct name and the right number of parameters
  // and parameter names
  var potentials = (from ele in type.GetMethods()
                    where ele.Name.Equals(name)
                    let param = ele.GetParameters()
                    where param.Length == types.Length
                    && param.Select(p => p.ParameterType.Name).SequenceEqual(types.Select(t => t.Name))
                    select ele);

  // Maybe check if we have more than 1? Or not?
  return potentials.FirstOrDefault();
 }
}

称为:

var myLookup = typeof(Enumerable).GetRuntimeMethodsExt("ToList", typeof(IEnumerable<>));

下面我附上了在编写我的第三个案例和两个案例时产生的IL。 ToList方法都没有产生任何结果。

// ToList<int>
IL_0001:  ldtoken     System.Collections.Generic.IEnumerable<System.Int32>
IL_0006:  call        System.Type.GetTypeFromHandle
IL_000B:  ldstr       "ToList"
IL_0010:  ldc.i4.1    
IL_0011:  newarr      System.Type
IL_0016:  stloc.3     // CS$0$0000
IL_0017:  ldloc.3     // CS$0$0000
IL_0018:  ldc.i4.0    
IL_0019:  ldtoken     System.Collections.Generic.IEnumerable<System.Int32>
IL_001E:  call        System.Type.GetTypeFromHandle
IL_0023:  stelem.ref  
IL_0024:  ldloc.3     // CS$0$0000
IL_0025:  call        System.Reflection.RuntimeReflectionExtensions.GetRuntimeMethod
IL_002A:  stloc.0     // _intToListMethod
// ToList<>
IL_002B:  ldtoken     System.Linq.Enumerable
IL_0030:  call        System.Type.GetTypeFromHandle
IL_0035:  ldstr       "ToList"
IL_003A:  ldc.i4.1    
IL_003B:  newarr      System.Type
IL_0040:  stloc.3     // CS$0$0000
IL_0041:  ldloc.3     // CS$0$0000
IL_0042:  ldc.i4.0    
IL_0043:  ldtoken     System.Collections.Generic.IEnumerable<>
IL_0048:  call        System.Type.GetTypeFromHandle
IL_004D:  stelem.ref  
IL_004E:  ldloc.3     // CS$0$0000
IL_004F:  call        System.Reflection.RuntimeReflectionExtensions.GetRuntimeMethod
IL_0054:  stloc.1     // _toListMethod
// Cast<>
IL_0055:  ldtoken     System.Linq.Enumerable
IL_005A:  call        System.Type.GetTypeFromHandle
IL_005F:  ldstr       "Cast"
IL_0064:  ldc.i4.1    
IL_0065:  newarr      System.Type
IL_006A:  stloc.3     // CS$0$0000
IL_006B:  ldloc.3     // CS$0$0000
IL_006C:  ldc.i4.0    
IL_006D:  ldtoken     System.Collections.Generic.IEnumerable<>
IL_0072:  call        System.Type.GetTypeFromHandle
IL_0077:  stelem.ref  
IL_0078:  ldloc.3     // CS$0$0000
IL_0079:  call        System.Reflection.RuntimeReflectionExtensions.GetRuntimeMethod
IL_007E:  stloc.2     // _castMethod

答案 1 :(得分:1)

你期待这个......

  

typeof(Enumerable).GetRuntimeMethod(“ToList”,new Type [] {typeof(IEnumerable&lt;&gt;)});

...要归还......

  

public static List ToList(此IEnumerable源代码);

...因为您假设参数JNICALL的类型等于source。它不是。参数typeof(IEnumerable<>)的类型是sourceIEnumerable<TSource>前者是后者的实例化(它是泛型类型定义),其中{{1}定义了泛型类型参数方法。

通常,很难定义一个简单的API来绑定到这样的方法,因为C#没有提供简单的方法(非反射)来获得表示在方法上定义的泛型参数的类型。