2010-08-10 15 views
6

LinQ contiene el método moldeada que arroja cada entrada en la lista para escribir T. Digamos que tenemos una lista que tiene el siguiente aspecto:LINQ moldeada <T> con System.Type

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

Un modelo de trabajo podría ser

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

Lo que me gustaría trabajar

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

Una solución sería utilizar reflexionar y genéricamente crear una lista y poblarla, pero me preguntaba si existe alguna solución mejor. Se enteró de que .NET 4.0 debería ser compatible con algunas co/contravariancias que pueden ser una forma de hacerlo.


extra Soulution información y reflexión

El error que consigo es la siguiente 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]. Tenga en cuenta que CrashEntry implementa IStaticEntry pero no se puede convertir porque es un tipo genérico de la lista.

que construye la siguiente solución a través de Stille lo haría como algo sin reflexión:

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 –

Respuesta

2

No es posible hacer esto estáticamente, como tampoco lo puede hacer con un solo objeto.

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

Sin embargo, es posible tratar los elementos dinámicamente de manera que no es necesaria una conversión al tipo subyacente:

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

Gracias por la respuesta, pero no creo que sea una solución al problema. Tengo una vista que espera un modelo de cierto tipo y obtuve el tipo como un parámetro. Se agregó algo de información sobre el error en la descripción del problema anterior –

+0

Si solo tiene el tipo de tiempo de ejecución (por ejemplo, una instancia de 'Tipo') y no el tipo de tiempo de compilación (p., un parámetro genérico ''), entonces debe usar reflection o 'dynamic' (y tendría que cambiar la vista para usar' dynamic'). Entonces, tus elecciones son: 1) Usa la reflexión; 2) use 'dynamic', cambiando la vista; 3) Pase el tipo como un parámetro genérico '' en lugar de una instancia 'Type'. –

+0

Bastante, gracias por la claridad sobre el tema. Con mi cantidad de tipeados, creo que la mejor manera es la solución Reflection para garantizar que las vistas sigan funcionando con modelos fuertemente tipados :) –

0

No es necesario echar algo en el tipo que usted sabrá sólo en tiempo de ejecución. El tipo del objeto no cambiará porque ejecutará el molde, si fue una cadena, será una cadena más adelante y no importa si lo asignará a una cadena o variable de objeto.

No necesita preocuparse por la fundición en un tipo de objeto real mientras está trabajando en métodos de reflexión. Puede permanecer como una variable de objeto porque al usar la reflexión puede acceder a todos sus miembros de tipo real sin ningún tipo de conversión.

+0

Agregué la descripción del error anterior, creo que da una idea más clara de lo que quiero decir. –

4

yo no entiendo muy bien por qué te gustaría hacer esto, pero se podría invocar Enumerable.Cast<T> través de la reflexión:

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

En cuyo caso, el tipo de tiempo de ejecución de stringSequence implementaría IEnumerable<string>.

+0

+1 Usted, señor, es tanto un caballero como un erudito. –