Bagaimana saya bisa memastikan bahwa FirstOrDefault <KeyValuePair> telah mengembalikan nilai

91

Berikut adalah versi sederhana dari apa yang saya coba lakukan:

var days = new Dictionary<int, string>();
days.Add(1, "Monday");
days.Add(2, "Tuesday");
...
days.Add(7, "Sunday");

var sampleText = "My favorite day of the week is 'xyz'";
var day = days.FirstOrDefault(x => sampleText.Contains(x.Value));

Karena 'xyz' tidak ada dalam kamus, metode FirstOrDefault tidak akan mengembalikan nilai yang valid. Saya ingin dapat memeriksa situasi ini tetapi saya menyadari bahwa saya tidak dapat membandingkan hasilnya dengan "null" karena KeyValuePair adalah sebuah struc. Kode berikut tidak valid:

if (day == null) {
    System.Diagnotics.Debug.Write("Couldn't find day of week");
}

Kami Anda mencoba untuk mengkompilasi kode, Visual Studio membuat kesalahan berikut ini:

Operator '==' cannot be applied to operands of type 'System.Collections.Generic.KeyValuePair<int,string>' and '<null>'

Bagaimana saya dapat memeriksa bahwa FirstOrDefault telah mengembalikan nilai yang valid?

desautelsj
sumber
1
Anda memiliki bug di sana, tetapi saya menganggap itu adalah masalah salin-tempel: hari bukanlah daftar, dan Anda tidak dapat menggunakan add on KeyValuePair.
Kobi
ooops ... Anda benar Saya mengetik dari memori dan saya jelas membuat kesalahan. Terima kasih telah menunjukkannya.
desautelsj
1
Mungkin: var days = new Dictionary <int, string> ();
Even Mien

Jawaban:

156

FirstOrDefaulttidak mengembalikan nol, ia mengembalikan default(T).
Anda harus memeriksa:

var defaultDay = default(KeyValuePair<int, string>);
bool b = day.Equals(defaultDay);

Dari MSDN -Enumerable.FirstOrDefault<TSource> :

default ( TSource ) jika sumber kosong; jika tidak, elemen pertama dalam sumber .

Catatan:

Kobi
sumber
17
+1, KeyValuePair adalah tipe nilai (struct), bukan tipe referensi (kelas) atau tipe nilai nullable, jadi tidak boleh null.
Lucas
6
@ paper1337 - Terima kasih, tapi di mana saya hilang typeof? Kode ini mengkompilasi dan berfungsi.
Kobi
3
Saya datang ke sini karena tidak jelas bagi saya, apa yang default(KeyValuePair<T1, T2>)akan terjadi. Ok, seharusnya sudah cukup jelas, bahwa itu akan menghasilkan KVP kosong. Tetapi karena "menjadi jelas" bukanlah pendekatan yang baik untuk menulis aplikasi yang tepat (dan implementasi saya saat ini terlalu rumit untuk memprovokasi kasus ini dengan jelas / rapi), saya mencobanya dengan proyek baru dan - memang - itu mengembalikan a KeyValuePairwith properties Keyand Valuebeing keduanya NULL.... hanya untuk menyelamatkan beberapa orang lain 5 menit kebodohan ini ;-)
Nicolas
@Nicolas - Tidak ada kebodohan di sini. Sebaiknya periksa sendiri dan pastikan Anda memahami kode Anda. Saya telah menambahkan tautan ke defaultkata kunci, jelas hilang di sini. Terima kasih!
Kobi
1
@JeffBridgman - Itu benar-benar poin yang bagus! Secara khusus di sini tidak mungkin, karena kami sedang bekerja dengan KeyValuePair. Jika Anda memiliki kode generik, day.Equalsbahkan tidak aman dari nol, dan saya akan menggunakanEqualityComparer<T>.Default.Equals(day, defaultDay)
Kobi
55

Ini cara yang paling jelas dan ringkas menurut saya:

var matchedDays = days.Where(x => sampleText.Contains(x.Value));
if (!matchedDays.Any())
{
    // Nothing matched
}
else
{
    // Get the first match
    var day = matchedDays.First();
}

Ini benar-benar berkeliling menggunakan barang nilai default yang aneh untuk struct.

perdamaian di luar
sumber
13
Masalah dengan ini, apakah ada potensi (tergantung pada implementasi) bahwa hari-hari yang dapat dihitung akan dihitung dua kali, atau bahkan lebih buruk, mengembalikan nilai yang berbeda antara panggilan Any () dan First ()
Ray Booysen
@RayBooysen Panggilan ToArray atau ToList memecahkan masalah dan Anda dapat menggunakan Count / Length dan Indexer.
Konsol
1
Perhatikan bahwa jawaban @ Ray tidak berlaku di sini, karena daysadalah a Dictionary<int,string>. Jadi itu akan dianggap sebagai IEnumerable<KeyValuePair<int,string>>, kemudian berperilaku seperti yang diharapkan ketika Any()dan First()dipanggil. Saya rasa ada implementasi lain yang dapat berperilaku berbeda seperti IEnumerable<>. Saya tidak tahu apakah saya melewatkan sesuatu.
Emanuele Bellini
0

Anda dapat melakukan ini sebagai gantinya:

var days = new Dictionary<int?, string>();   // replace int by int?
days.Add(1, "Monday");
days.Add(2, "Tuesday");
...
days.Add(7, "Sunday");

var sampleText = "My favorite day of the week is 'xyz'";
var day = days.FirstOrDefault(x => sampleText.Contains(x.Value));

lalu :

if (day.Key == null) {
    System.Diagnotics.Debug.Write("Couldn't find day of week");
}
Jocelyn Marcotte
sumber