2010-08-10 14 views
6

LinQ enthält die Methode Guss die jeden Eintrag in der Liste wirft T einzugeben. Lassen Sie uns sagen wir eine Liste haben, die wie folgt aussieht:Linq Guss <T> mit System.Type

List<Object> obj = new List<Object>(); 
obj.Add("A"); 
obj.Add("B"); 

Ein Arbeitsmodell

var list = obj.Cast<string>(); 

sein könnte Was würde Ich mag

Type t = typeof(String); 
Object list = obj.Cast(t); 

Eine Lösung wäre die Verwendung arbeiten Reflexion und generische erstellen Sie eine Liste und füllen Sie es, aber ich frage mich, ob es eine bessere Lösung gibt? Gehört, dass .NET 4.0 einige Co/Kontravarianz unterstützen sollte, was ein Weg dazu sein könnte.


Zusätzliche Informationen und Reflexion Soulution

Der Fehler ich erhalte, ist die folgende The model item passed into the dictionary is of type System.Collections.Generic.List1[IStatisticEntry], but this dictionary requires a model item of type System.Collections.Generic.List1[CrashStatistic+CrashEntry]. Beachten Sie, dass CrashEntry IStaticEntry implementiert, aber nicht gegossen werden kann, da es sich um einen generischen Typ der Liste handelt.

Ich konstruierte folgende Lösung durch würde ich stille wie etwas ohne Reflexion:

public static object Cast(this IEnumerable list, Type type) 
    { 
     var newList = Activator.CreateInstance(typeof(List<>).MakeGenericType(type)); 

     foreach (var item in list) 
      newList.GetType().GetMethod("Add").Invoke(newList, new object[] { item }); 

     return newList; 
    } 
+0

http://geekswithblogs.net/abhijeetp/archive/2010/01/10/covariance-and-contravariance-in-c-4.0.aspx –

Antwort

2

Es ist nicht möglich, dies statisch zu tun, genauso wenig wie mit einem einzelnen Objekt.

Type t = typeof(string); 
var x = (t)obj; // invalid 

Allerdings ist es möglich, die Elemente dynamisch zu behandeln, so dass eine Umwandlung in den zugrunde liegenden Typ nicht notwendig ist:

static void Main(string[] args) 
{ 
    List<Object> obj = new List<Object>(); 
    obj.Add("A"); 
    obj.Add("B"); 

    var list = obj.Cast<dynamic>(); 
    foreach (var item in list) 
    { 
     Console.WriteLine(item[0]); 
    } 

    Console.ReadKey(); 
} 
+0

Vielen Dank für die Antwort, aber ich denke nicht, dass das Problem behoben ist. Ich habe eine Ansicht, die ein Modell eines bestimmten Typs erwartet, und ich habe den Typ als Parameter erhalten. Es wurden einige Informationen zum Fehler in der obigen Problembeschreibung hinzugefügt. –

+0

Wenn Sie nur den Laufzeittyp (z. B. eine Instanz von 'Type') und nicht den Kompilierzeittyp (z., ein '' generischer Parameter), dann müssen Sie reflection oder 'dynamic' verwenden (und Sie müssten die Ansicht ändern, um' dynamic' zu verwenden). Also, Ihre Möglichkeiten sind: 1) Verwenden Sie Reflexion; 2) benutze 'dynamisch', ändere die Ansicht; 3) Übergeben Sie den Typ als generischen Parameter '' anstelle einer 'Type'-Instanz. –

+0

Fair genug, danke für die Klarheit zu diesem Thema. Mit meiner Menge an Tippfehlern glaube ich, dass der schönste Weg die Reflection-Lösung ist, um sicherzustellen, dass die Ansichten immer noch mit stark typisierten Modellen funktionieren. –

0

Sie brauchen nicht etwas von der Art zu werfen, die Sie nur in Laufzeit kennen. Der Typ des Objekts ändert sich nicht, weil Sie eine Umwandlung durchführen, wenn es eine Zeichenfolge ist, wird es später eine Zeichenfolge sein, und es spielt keine Rolle, ob Sie es einer Zeichenfolge oder einer Objektvariablen zuweisen.

Sie müssen sich nicht um das Umwandeln in einen echten Objekttyp kümmern, während Sie mit Reflektionsmethoden arbeiten. Es kann als Objektvariable bleiben, da Sie während der Reflektion auf alle Mitglieder des realen Typs zugreifen können, ohne dass eine Umwandlung erfolgt.

+0

Ich fügte die obige Fehlerbeschreibung hinzu, denke, es gibt eine klarere Vorstellung davon was ich meine. –

4

Ich verstehe nicht ganz, warum Sie wollen würden tun dies aber man konnte Enumerable.Cast<T> durch Reflexion aufrufen:

List<object> objectList = new List<object> { "Foo", "Bar" }; 
object stringSequence = typeof(Enumerable) 
    .GetMethod("Cast", BindingFlags.Public | BindingFlags.Static) 
    .MakeGenericMethod(typeof(string)) 
    .Invoke(null, new[] { objectList }); 

In diesem Fall wird die Laufzeittyp von stringSequence würde IEnumerable<string> implementieren.

+0

+1 Sie, Sir, sind sowohl ein Gentleman als auch ein Gelehrter. –