2010-08-10 21 views
6

LinQ contiene il metodo Fusioni che getta ogni voce nell'elenco di digitare T. Consente di dire che abbiamo una lista che si presenta come il seguente:Linq Fusioni <T> con System.Type

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

Un cast di lavoro potrebbe essere

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

Quello che mi piacerebbe lavorare

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

Una soluzione potrebbe essere quella di utilizzare riflessione e genericamente creare un elenco e popolarlo, ma mi chiedevo se esiste una soluzione migliore? Ho sentito che .NET 4.0 dovrebbe supportare qualche co/contro-varianza che potrebbe essere un modo per farlo.


informazione e di riflessione supplementare Soulution

L'errore che ottengo è la seguente 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]. Nota che CrashEntry implementa IStaticEntry ma non può essere castato perché è un tipo generico della lista.

ho costruito la seguente soluzione attraverso lo farei stille come qualcosa senza riflettere:

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 –

risposta

2

Non è possibile eseguire questa operazione staticamente, non più di quanto non si possa fare con un singolo oggetto.

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

Tuttavia, è possibile trattare gli elementi in modo dinamico in modo che un cast al tipo di fondo non è necessaria:

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

Grazie per la risposta, ma non penso che sia una soluzione al problema. Ho una vista che si aspetta un modello di un certo tipo e ho ottenuto il tipo come parametro. Aggiunte alcune informazioni sull'errore nella descrizione del problema sopra –

+0

Se si ha solo il tipo di runtime (ad es. Un'istanza di 'Tipo') e non il tipo in fase di compilazione (ad es., un parametro generico '', allora devi usare reflection o 'dynamic' (e dovresti cambiare la vista per usare' dynamic'). Quindi, le tue scelte sono: 1) Usa la riflessione; 2) usa 'dynamic', cambiando la vista; 3) Passa il tipo come parametro generico '' invece di un'istanza 'Tipo'. –

+0

Abbastanza giusto, grazie per la chiarezza sull'argomento. Con la mia quantità di errori di battitura credo che il modo migliore sia la soluzione Reflection per garantire che le viste funzionino ancora con modelli fortemente tipizzati :) –

0

Non è necessario gettare qualcosa sul tipo che si sa solo in fase di esecuzione. Il tipo dell'oggetto non cambierà perché eseguirai cast, se fosse una stringa sarà una stringa successiva e non importa se la assegnerai alla variabile stringa o oggetto.

Non è necessario preoccuparsi della trasmissione a un tipo di oggetto reale mentre si sta utilizzando i metodi di riflessione. Può rimanere come variabile di un oggetto, perché mentre si usa il reflection è possibile accedere a tutti i membri del tipo reale in ogni caso, senza alcun cast.

+0

Ho aggiunto la descrizione dell'errore sopra, penso che dia un'idea più chiara di ciò che intendo. –

4

Io non capisco perché ci si vuole fare questo, ma si potrebbe invocare Enumerable.Cast<T> attraverso la riflessione:

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 questo caso il tipo di runtime di stringSequence attuerebbe IEnumerable<string>.

+0

+1 Tu, signore, sei sia un gentiluomo che uno studioso. –

Problemi correlati