Czy LINQ działa z IEnumerable?

87

Mam klasę, która implementuje IEnumerable, ale nie implementuje IEnumerable<T>. Nie mogę zmienić tej klasy i nie mogę zamiast niej użyć innej klasy. Jak zrozumiałem z MSDN LINQ może być używany, jeśli klasa implementujeIEnumerable<T> . Próbowałem użyć instance.ToQueryable(), ale nadal nie włącza metod LINQ. Wiem na pewno, że ta klasa może zawierać instancje tylko jednego typu, więc klasa mogłaby zaimplementować IEnumerable<T>, ale tak po prostu nie jest. Więc co mogę zrobić, aby wykonać zapytanie o tę klasę przy użyciu wyrażeń LINQ?

Bogdan Verbenets
źródło
Bez rzutowania IEnumerable, zamiast wszystkich metod linq zobaczysz tylko 8 metod: AsQueryable, Cast <>, Equals, GetEnumerator, GetHashCode, GetType, OfType <>, ToString
ShawnFeatherly

Odpowiedzi:

135

Możesz użyć Cast<T>()lub, OfType<T>aby uzyskać ogólną wersję IEnumerable, która w pełni obsługuje LINQ.

Na przykład.

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

Lub jeśli nie wiesz, jaki typ zawiera, zawsze możesz to zrobić:

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

Jeśli Twój nieogólny IEnumerablezawiera obiekty różnego typu, a interesują Cię tylko np. struny, które możesz zrobić:

IEnumerable<string> strings = objects.OfType<string>();
DeCaf
źródło
2
Każdego dnia uczę się czegoś nowego o LINQ. Każdego dnia coraz bardziej to kocham.
João Mendes
11

Tak, może. Wystarczy użyć tej Cast<T>funkcji, aby przekonwertować ją na wpisany IEnumerable<T>. Na przykład:

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

Teraz e2jest IEnumerable<T>i może współpracować ze wszystkimi funkcjami LINQ.

JaredPar
źródło
3

Możesz również użyć składni przetwarzania zapytań LINQ, która rzutuje na typ zmiennej zakresu ( itemw tym przykładzie), jeśli typ jest określony:

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

Efekt jest identyczny z rozwiązaniem @ JaredPar; Aby uzyskać szczegółowe informacje, zobacz 7.16.2.2: Jawne typy zmiennych zakresu w specyfikacji języka C #.

TrueWill
źródło