Does anyone have any clue on why calling GetRuntimeMethod is returning null for the following case?
_toListMethod = typeof(Enumerable).GetRuntimeMethod("ToList", new Type[] { typeof(IEnumerable<>) });
It should work just like it does for:
_castMethod = typeof(Enumerable).GetRuntimeMethod("Cast", new Type[] { typeof(IEnumerable) });
I tried to debug this by running the following code:
var bah = typeof (Enumerable).GetRuntimeMethods().Where(m => m.Name.Contains("ToList"));
var derp = bah.First().GetParameters();
To my surprise, the first line returns a collection which contains the MethodInfo I am trying to get and the second line confirms that the expected paramter type is IEnumerable<>.
The two method signatures, Cast and ToList, are similar and I cannot see any reason why getting the MethodInfo for ToList would fail.
This code is running on a Portable Class Library with TargetFrameworkProfile set to Profile78.
Thanks!
Update: Until I have a good solution, there is one ugly workaround which works for me:
_toListMethod = typeof(Enumerable).GetRuntimeMethods().First(m => m.Name.Contains("ToList"));
I looked up the signatures, and they look like this:
public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source);
public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source);
I believe there might be something fishy going on with GetRunTimeMethod
and extension methods with generic parameters since this does not work:
var intToListMethod = typeof(IEnumerable<int>).GetRuntimeMethod("ToList", new Type[] { typeof(IEnumerable<int>) });
I took some time and tried to create a valid extension method for your needed behaviour, and I came up with the code snippet below. It works for me.
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();
}
}
Called as this:
var myLookup = typeof(Enumerable).GetRuntimeMethodsExt("ToList", typeof(IEnumerable<>));
Below I've attached the IL produced when compiling my third case and your two cases. None of the ToList
methods produce any result.
// 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
You expect this...
typeof(Enumerable).GetRuntimeMethod("ToList", new Type[] { typeof(IEnumerable<>) });
...to return this...
public static List ToList(this IEnumerable source);
...because you assume the type of the parameter source
is equal to typeof(IEnumerable<>)
. It is not. The type of the parameter source
is IEnumerable<TSource>
while typeof(IEnumerable<>)
the former is an instantiation of the latter (which is the generic type definition) with the generic type parameter defined by the ToList
method.
In general, it's difficult to define a simple API for binding to such methods because C# provides no simple way (non-reflection) to get a type representing a generic parameter defined on a method.