2014-01-23 27 views
8

Hat jemand Ahnung, warum Aufruf von GetRuntimeMethod Null für den folgenden Fall zurückgibt?RuntimeReflectionExtensions.GetRuntimeMethod funktioniert nicht wie erwartet

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

Es sollte funktionieren wie es funktioniert für:

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

ich versucht, dies zu debuggen, indem Sie den folgenden Code ausführen:

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

Zu meiner Überraschung, die erste Zeile liefert ein Sammlung, die das MethodInfo enthält, das ich versuche, zu erhalten, und die zweite Zeile bestätigt, dass der erwartete Parametertyp IEnumerable ist <>.

Die beiden Methodensignaturen Cast und ToList sind ähnlich, und ich kann keinen Grund sehen, warum das Abrufen von MethodInfo für ToList fehlschlagen würde.

Dieser Code wird in einer Portable Class Library mit TargetFrameworkProfile auf Profile78 ausgeführt.

Danke!

Update: Bis ich eine gute Lösung haben, gibt es eine hässlich Abhilfe, die für mich funktioniert:

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

Antwort

3

ich die Unterschriften nachgeschlagen, und sie sehen wie folgt aus:

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

Ich glaube, könnte etwas faul weiter mit GetRunTimeMethod und Erweiterung Methoden mit generischen Parameter sein, da dies nicht funktioniert:

Ich habe einige Zeit genommen und versucht, eine gültige Erweiterungsmethode für Ihr benötigtes Verhalten zu erstellen, und ich kam mit dem Codeausschnitt unten. Für mich geht das.

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

wie dies Genannt:

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

Im Folgenden wird ich die IL angebracht habe produziert, wenn meinen dritten Fall und Ihre beiden Fälle zusammenzustellen. Keines der ToList Methoden erzeugt irgendein Ergebnis.

// 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 
+0

Guter Punkt. Die Cast-Methode hat einen nicht generischen Parametertyp. Ich stimme Ihnen zu, es sieht so aus, als ob es etwas mit generischen Parametertypen zu tun hat. –

+1

@TiagoMargalho Ich habe eine funktionierende Erweiterungsmethode hinzugefügt (hoffentlich hat copy-paste nichts kaputt gemacht), die die möglichen Methoden durchläuft und den Namen der Typparameter überprüft. Funktioniert prächtig in diesem Fall, obwohl ich glaube, es ist ein gefährlicher Weg zu gehen :) – flindeberg

0

du erwarten ...

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

... dies zurück ...

public static List ToList (diese IEnumerable Quelle);

... weil Sie die Art des Parameters übernehmen ist source zu typeof(IEnumerable<>) gleich. Es ist nicht.Der Typ des Parameters source ist IEnumerable<TSource>, während typeof(IEnumerable<>) ersterer eine Instanziierung des letzteren ist (was die generische Typdefinition ist) mit dem generischen Typparameter, der durch die Methode ToList definiert wird.

Im Allgemeinen ist es schwierig, eine einfache API für die Bindung an solche Methoden zu definieren, da C# keine einfache Möglichkeit bietet, einen Typ zu erhalten, der einen in einer Methode definierten generischen Parameter darstellt.

Verwandte Themen