¿LINQ funciona con IEnumerable?

87

Tengo una clase que implementa IEnumerable, pero no implementa IEnumerable<T>. No puedo cambiar esta clase y no puedo usar otra clase en su lugar. Como he entendido de MSDN, LINQ se puede usar si la clase implementaIEnumerable<T> . Intenté usar instance.ToQueryable(), pero todavía no habilita los métodos LINQ. Estoy seguro de que esta clase puede contener instancias de un solo tipo, por lo que la clase podría implementar IEnumerable<T>, pero simplemente no lo hace. Entonces, ¿qué puedo hacer para consultar esta clase usando expresiones LINQ?

Bogdan Verbenets
fuente
Sin emitir IEnumerable, en lugar de todos los métodos linq, solo verá 8 métodos: AsQueryable, Cast <>, Equals, GetEnumerator, GetHashCode, GetType, OfType <>, ToString
ShawnFeatherly

Respuestas:

134

Puede usar Cast<T>()o OfType<T>para obtener una versión genérica de un IEnumerable que sea totalmente compatible con LINQ.

P.ej.

IEnumerable objects = ...;
IEnumerable<string> strings = objects.Cast<string>();

O si no sabe qué tipo contiene, siempre puede hacer:

IEnumerable<object> e = objects.Cast<object>();

Si su no genérico IEnumerablecontiene objetos de varios tipos y solo está interesado en, por ejemplo. las cadenas que puedes hacer:

IEnumerable<string> strings = objects.OfType<string>();
Descafeinado
fuente
2
Todos los días aprendo algo nuevo sobre LINQ. Cada día lo amo más y más.
João Mendes
11

Sí puede. Solo necesita usar la Cast<T>función para convertirlo en un IEnumerable<T>. Por ejemplo:

IEnumerable e = ...;
IEnumerable<object> e2 = e.Cast<object>();

Ahora e2es un IEnumerable<T>y puede trabajar con todas las funciones de LINQ.

JaredPar
fuente
3

También puede usar la sintaxis de comprensión de consultas de LINQ, que se convierte en el tipo de la variable de rango ( itemen este ejemplo) si se especifica un tipo:

IEnumerable list = new ArrayList { "dog", "cat" };

IEnumerable<string> result =
  from string item in list
  select item;

foreach (string s in result)
{
    // InvalidCastException at runtime if element is not a string

    Console.WriteLine(s);
}

El efecto es idéntico a la solución de @ JaredPar; consulte 7.16.2.2: Tipos de variables de rango explícitos en la especificación del lenguaje C # para obtener más detalles.

TrueWill
fuente