Menggunakan sintaks metode ekstensi LINQ pada MatchCollection

92

Saya memiliki kode berikut:

MatchCollection matches = myRegEx.Matches(content);

bool result = (from Match m in matches
               where m.Groups["name"].Value.Length > 128
               select m).Any();

Apakah ada cara untuk melakukan ini menggunakan sintaks metode ekstensi LINQ?

Sesuatu seperti ini:

bool result = matches.Any(x => ... );
Thomas
sumber

Jawaban:

196
using System.Linq;

matches.Cast<Match>().Any(x => x.Groups["name"].Value.Length > 128)

Anda hanya perlu mengonversinya dari sebuah IEnumerableke IEnumerable<Match>(IEnumerable <T>) untuk mendapatkan akses ke ekstensi LINQ yang disediakan di IEnumerable <T>.

msarchet.dll
sumber
Siapa yang memberikan suara untuk setiap jawaban di sini? Jawaban ini mendapat suara positif saya, para cognrat.
Kevin Kalitowski
+1 Saya mencoba mencari tahu mengapa ini tidak disukai. Saya tidak melihatnya.
jason
Saya benar-benar bingung bagaimana ini diturunkan sebagai yang benar
msarchet
1
Ini berfungsi, pastikan Anda melakukannya dengan cara using System.Linqlain itu akan memberikan kesalahan sintaksis
Ash Berlin-Taylor
1
Terima kasih, kepada siapa pun yang bingung, Casttidak diperlukan sejak C # 8.0, tetapi kode tidak dapat dikompilasi dalam versi bahasa sebelumnya jika tidak tersedia.
rvnlord
46

Saat Anda menentukan tipe variabel rentang eksplisit , kompilator menyisipkan panggilan ke Cast<T>. Jadi ini:

bool result = (from Match m in matches
               where m.Groups["name"].Value.Length > 128
               select m).Any();

persis sama dengan:

bool result = matches.Cast<Match>()
                     .Where(m => m.Groups["name"].Value.Length > 128)
                     .Any();

yang juga bisa ditulis sebagai:

bool result = matches.Cast<Match>()
                     .Any(m => m.Groups["name"].Value.Length > 128);

Dalam hal ini Castpanggilan diperlukan karena MatchCollectionhanya mengimplementasikan ICollectiondan IEnumerable, tidak IEnumerable<T>. Hampir semua metode ekstensi LINQ ke Objek ditargetkan IEnumerable<T>, dengan pengecualian penting dari Castdan OfType, keduanya digunakan untuk mengubah kumpulan yang diketik "lemah" (seperti MatchCollection) menjadi generik IEnumerable<T>- yang kemudian memungkinkan untuk operasi LINQ lebih lanjut.

Jon Skeet
sumber
8

Coba ini:

var matches = myRegEx.Matches(content).Cast<Match>();

Untuk referensi, silakan lihat Enumerable.Cast:

Mengonversi elemen dari menjadi IEnumerabletipe yang ditentukan.

Pada dasarnya, ini adalah salah satu cara untuk mengubah file IEnumerablemenjadi IEnumerable<T>.

Andrew Hare
sumber
+1 Saya mencoba mencari tahu mengapa ini tidak disukai. Saya tidak melihatnya.
jason
@Jason: Kemungkinan besar seseorang mencoba meningkatkan jawaban mereka.
Andrew Hare
3

Saya pikir itu akan menjadi seperti ini:

bool result = matches.Cast<Match>().Any(m => m.Groups["name"].Value.Length > 128);
pstrjds.dll
sumber
1
Tidak. Intinya adalah MatchCollectionhanya mengimplementasikan IEnumerable. Ini tidak diketik dengan kuat.
jason
2

Anda dapat mencoba sesuatu seperti ini:

List<Match> matchList = matches.Cast<Match>().Where(m => m.Groups["name"].Value.Length > 128).ToList();
James Johnson
sumber
-1

EDIT:

 public static IEnumerable<T> AsEnumerable<T>(this IEnumerable enumerable)
 {
      foreach(object item in enumerable)
          yield return (T)item;
 }

Maka Anda harus dapat memanggil metode ekstensi ini untuk mengubahnya menjadi IEnumerable:

 matches.AsEnumerable<Match>().Any(x => x.Groups["name"].Value.Length > 128);
Tejs
sumber
Ini lebih baik dariku, aku tidak ingat Any mengambil predikat.
pstrjds
Tidak. Intinya adalah MatchCollectionhanya mengimplementasikan IEnumerable. Ini tidak diketik dengan kuat.
jason
@Jason kecuali bahwa itu dapat ditransmisikan ke IEnumberable <T> melalui IEnumberable.Cast <T>
msarchet
@msarchet: Ya, saya tahu, itulah sebabnya saya memberi suara positif pada jawaban Anda. Jawaban ini, sebelum diedit, bahkan tidak akan dikompilasi.
jason