2009-05-01 14 views
44

ich eine Klasse (A Web Control) haben, die eine Eigenschaft des Typs hat IEnumerable und möchte mit dem Parameter arbeiten LINQ verwenden.konvertieren/Cast IEnumerable IEnumerable <T>

Gibt es eine Möglichkeit, über Reflektion zu IEnumerable zu <T> cast/convert/zu konvertieren/> nicht den Typ zur Kompilierzeit wissen?

Method void (IEnumerable source) 
{ 
    var enumerator = source.GetEnumerator(); 

    if (enumerator.MoveNext()) 
    { 
     var type = enumerator.Current.GetType(); 
     Method2<type>(source); // this doesn't work! I know! 
    } 
} 

void Method2<T>(IEnumerable<T> source) {} 

Antwort

56

Hat Ihr Method2 wirklich egal, welche Art es erhält? Wenn nicht, könnten Sie einfach Cast<object>() nennen:

void Method (IEnumerable source) 
{ 
    Method2(source.Cast<object>()); 
} 

Wenn Sie auf jeden Fall die richtige Art bekommen müssen, müssen Sie Reflektion verwenden.

Etwas wie:

MethodInfo method = typeof(MyType).GetMethod("Method2"); 
MethodInfo generic = method.MakeGenericMethod(type); 
generic.Invoke(this, new object[] {source}); 

Es ist zwar nicht ideal ... insbesondere, wenn die Quelle nicht genau ist ein IEnumerable<type> dann wird der Aufruf fehl. Zum Beispiel, wenn das erste Element eine Zeichenfolge ist, aber die Quelle ist ein List<object>, werden Sie Probleme haben. Diese

+0

umwandeln. Je nach Situation können Sie auch 'OfType' verwenden, nur darauf hinweisend. Siehe auch: http://stackoverflow.com/questions/4015930/when-to-use-cast-and-oftype-in-linq –

8

Sie wahrscheinlich Ihren Code Refactoring wollen IEnumerable.Cast<T>

Verwenden Sie verwenden, um es wie folgt aus:

IEnumerable mySet = GetData(); 
var query = from x in mySet.Cast<int>() 
      where x > 2 
      select x; 
+0

den Typ bei der Kompilierung erforderlich. Gleicher Fehler. – andleer

+0

Das ist richtig. Und so auch Methode2. Sie können immer auf einen IEnumerable ... –

2

ist Jahre später, aber ich löste das Problem List<Object>.

void Method(IEnumerable source) 
{ 
    var enumerator = source.GetEnumerator(); 
    if (enumerator.MoveNext()) 
    { 
     MethodInfo method = typeof(MyClass).GetMethod("Method2"); 
     MethodInfo generic; 
     Type type = enumerator.Current.GetType(); 
     bool sameType = true; 

     while (enumerator.MoveNext()) 
     { 
      if (enumerator.Current.GetType() != type) 
      { 
       sameType = false; 
       break; 
      } 
     } 

     if (sameType) 
      generic = method.MakeGenericMethod(type); 
     else 
      generic = method.MakeGenericMethod(typeof(object)); 

     generic.Invoke(this, new object[] { source }); 
    } 
} 
3

Mit 4 .NET können Sie einfach source-dynamic werfen, bevor es an Methode übergeben. Dies wird die korrekte allgemeine Überlastung verursachen, ohne hässliche Reflexion Code zur Laufzeit aufgelöst werden:

void Method(IEnumerable source) 
{ 
    var enumerator = source.GetEnumerator(); 

    if (enumerator.MoveNext()) 
    { 
     Method2((dynamic)source); 
    } 
} 

Wie bei Jons zweiter Lösung, wird dies nur funktionieren, wenn Ihre Quelle tatsächlich ein IEnumerable<T> ist. Wenn es eine einfache IEnumerable ist dann müssen Sie eine andere Methode erstellen, die es auf den richtigen IEnumerable<T> Typ konvertiert, wie in der folgenden Lösung:

IEnumerable<T> Convert<T>(IEnumerable source, T firstItem) 
{ 
    // Note: firstItem parameter is unused and is just for resolving type of T 
    foreach(var item in source) 
    { 
     yield return (T)item; 
    } 
} 

void Method(IEnumerable source) 
{ 
    var enumerator = source.GetEnumerator(); 

    if (enumerator.MoveNext()) 
    { 
     dynamic firstItem = enumerator.Current; 
     dynamic typedEnumerable = Convert(source, firstItem); 
     Method2(typedEnumerable); 
    } 
}