2012-12-02 3 views
5

unbekannt ist, ich habe eine Sortier Extension-Methode mit folgenden Signatur:Cast IEnumerable IEnumerable <T> wenn T bei der Kompilierung

public static IEnumerable<T> CustomSort<T>(this IEnumerable<T> source, string sortProperties) 

Ich schrieb eine Weile zurück, und es hat seine Sache getan. Jetzt erstelle ich ein benutzerdefiniertes Steuerelement und die DataSource-Eigenschaft ist ein IEnumerable (nicht-generisch). Gibt es eine Möglichkeit, den Typ der Objekte in einem nicht generischen IEnumerable zu erhalten?

Ich bin sicher, dass das Problem der "Sortieren einer benutzerdefinierten Steuerdatenquelle" eine Million Mal gelöst wurde, aber ich kann einfach nicht scheinen, eine Lösung zu finden.

Antwort

1

Sie könnten eine Erweiterungsmethode erstellen, die den richtigen Typ zur Laufzeit zurück:

public static class LinqExtensions 
{ 
    public static Type GetElementType(this IEnumerable source) 
    { 
     var enumerableType = source.GetType(); 
     if (enumerableType.IsArray) 
     { 
      return enumerableType.GetElementType(); 
     } 
     if (enumerableType.IsGenericType) 
     { 
      return enumerableType.GetGenericArguments().First(); 
     } 
     return null; 
    } 
} 

Update: Ich habe den Mechanismus hinzugefügt, die ich verwenden würde die allgemeine spezifische IEnumerable<T> Sortierung auf der nicht ausführen generic IEnumerable

public static class SortingExtensions 
{ 
    public static IEnumerable<T> CustomSort<T>(this IEnumerable<T> source, string sortProperties) 
    { 
     // sort here 
    } 

    public static IEnumerable CustomSort(this IEnumerable source, string sortProperties) 
    { 
     var elementType = source.GetElementType(); 
     var genericElementType = typeof (IEnumerable<>).MakeGenericType(elementType); 

     var sortMethod = typeof (SortingExtensions).GetMethod(
      "CustomSort", 
      BindingFlags.Public | BindingFlags.Static, 
      null, 
      new [] {genericElementType, typeof (string)}, 
      null); 

     return (IEnumerable) sortMethod.Invoke(null, new object[] {source, sortProperties}); 
    } 

} 
+0

Interessanter Ansatz. Ich werde es auch versuchen. Bei der Sortiermethode ist dies mehr oder weniger das, was wir tun, aber wir berücksichtigen auch die Sortierung mit mehreren Eigenschaften, von denen jede ihre eigene Richtung hat. –

+0

Ich habe Ihre Lösung versucht, aber enumerableType.GetGenericArguments(). First() verursacht eine StackOverflowException. (Havn hatte eine von diesen in Ewigkeiten! :)) –

+0

Ich fand das Problem. Sobald die Methode den öffentlichen statischen IEnumerable CustomSort (diese IEnumerable-Quelle, String sortProperties) durchlaufen hat, wird sie erneut aufgerufen, und dies erzeugt eine infinate-Schleife, oder so scheint es. –

1

Persönlich würde ich nur

DataSource.Cast<object>() 

und dann haben Sie eine IEnumerable<object>, die Sie in Ihrer CustomSort<T> Funktion verwenden können. Ich gehe hier davon aus, dass diese Funktion bereits beliebige Objekte behandeln kann; Nach dem zweiten Parameternamen zu schätzen, nehme ich an, dass Sie Reflection trotzdem verwenden, also sollte es in Ordnung sein. Stellen Sie sicher, dass es die GetType() jedes Objekts verwendet, wenn Sie darüber reflektieren, nicht typeof(T), weil typeof(T) wird offensichtlich object und es wird nicht die Liste der Felder des tatsächlichen Objekts.

Natürlich, wenn Sie tatsächlich die Art aller Objekte in der Datenquelle zur Compile-Zeit kennen, können Sie stattdessen diese Art verwenden, zB:

DataSource.Cast<Customer>() 
+0

Sie haben Recht mit der MoveNext(). Ich habe diese Zeile bereits gelöscht, als ich diesen Beitrag erstellt habe, also habe ich aus dem Speicher geschrieben. Über die Besetzung <>, ich werde es versuchen. Vielen Dank! –

+0

@EladLachmi: OK, dann nehme ich mir die Freiheit, diesen Teil auch von deiner Frage zu entfernen. – Timwi

+0

Die Funktion CustomSort verwendet typeof (T) in Reflektion, um die Sortierung als Lambda-Ausdruck zu erstellen. Ich würde lieber das nutzen, was wir haben, als etwas Neues zu kreieren (was durch QA, etc, etc gehen muss, etc ... Sie wissen, wie es ist :)) –

4

Es ist eine grundlegende Frage hier dass ein Typ IEnumerable-of-T für mehrere T gleichzeitig implementieren kann. Aber wenn wir diesen Fall auszuschließen, ein frecher Ansatz ist:

void Evil<T>(IEnumerable<T> data) {...} 

IEnumerable source = ... 
dynamic cheeky = source; 
Evil(cheeky); 

Diese auslagert im Grunde dieses Problem mit dem DLR, lassen Sie Ihre Evil-of-T-Methode es einfach.

+1

Dies setzt voraus, dass 'source' tatsächlich' IEnumerable 'implementiert für einige "T"; Viele Datenquellen in .NET stammen aus der Zeit vor Generics und implementieren daher eigentlich nur 'IEnumerable'. In diesem Fall stürzt Ihr Code mit einer 'RuntimeBinderException' ab. – Timwi

+0

@Timwi die Frage fragt nach "Casting". Es ist nur möglich, es zu übertragen, wenn es tatsächlich die generische Version für einige T implementiert. Ich stimme dir nicht zu - ich sage nur, dass diese Abhängigkeit in der Frage impliziert ist. –

+0

@Timwi - Marc ist in seiner Annahme korrekt, dass der Ursprung des nicht-generischen IEnumerable (die DataSource) eine Liste von einigen T ist, die mir zur Kompilierungszeit unbekannt ist.Daher sollte IEnumerable implementiert werden. –

Verwandte Themen