ฉันจะแน่ใจได้อย่างไรว่า FirstOrDefault <KeyValuePair> ส่งคืนค่า


91

นี่เป็นเวอร์ชันที่เรียบง่ายของสิ่งที่ฉันกำลังพยายามทำ:

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

เนื่องจากไม่มี 'xyz' ในพจนานุกรมเมธอด FirstOrDefault จะไม่ส่งคืนค่าที่ถูกต้อง ฉันต้องการตรวจสอบสถานการณ์นี้ แต่ฉันตระหนักดีว่าฉันไม่สามารถเปรียบเทียบผลลัพธ์กับ "null" ได้เนื่องจาก KeyValuePair เป็นโครงสร้าง รหัสต่อไปนี้ไม่ถูกต้อง:

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

เราพยายามรวบรวมโค้ด Visual Studio แสดงข้อผิดพลาดต่อไปนี้:

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

ฉันจะตรวจสอบได้อย่างไรว่า FirstOrDefault ส่งคืนค่าที่ถูกต้อง


1
คุณมีข้อบกพร่องอยู่ที่นั่น แต่ฉันคิดว่ามันเป็นสิ่งที่คัดลอกวาง: วันไม่ใช่รายการและคุณไม่สามารถใช้เพิ่มใน KeyValuePair
Kobi

อ๊ะ ... คุณพูดถูกฉันพิมพ์จากหน่วยความจำและฉันทำผิดพลาด ขอบคุณที่ชี้ให้เห็น
desautelsj

1
อาจเป็น: var days = พจนานุกรมใหม่ <int, string> ();
แม้นเมี่ยน

คำตอบ:


156

FirstOrDefaultไม่ได้กลับ null default(T)ก็จะส่งกลับ
คุณควรตรวจสอบ:

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

จากMSDN -Enumerable.FirstOrDefault<TSource> :

ค่าเริ่มต้น ( TSource ) หากแหล่งข้อมูลว่างเปล่า มิฉะนั้นองค์ประกอบแรกในแหล่งที่มา

หมายเหตุ:


17
+1, KeyValuePair เป็นประเภทค่า (struct) ไม่ใช่ประเภทอ้างอิง (คลาส) หรือประเภทค่าว่างดังนั้นจึงไม่สามารถเป็นค่าว่างได้
Lucas

6
@ paper1337 - ขอบคุณ แต่ฉันหายไปtypeofไหน? รหัสนี้รวบรวมและใช้งานได้
Kobi

3
ฉันมาที่นี่เพราะมันไม่ชัดเจนสำหรับฉันว่าdefault(KeyValuePair<T1, T2>)จะเกิดอะไรขึ้นโอเคมันควรจะค่อนข้างชัดเจนว่ามันจะทำให้ KVP ว่างเปล่า แต่เนื่องจาก "ชัดเจน" ไม่ใช่แนวทางที่ดีในการเขียนแอปพลิเคชันที่เหมาะสม (และการใช้งานปัจจุบันของฉันซับซ้อนเกินไปที่จะกระตุ้นให้เกิดกรณีนี้อย่างชัดเจน / หมดจด) ฉันจึงลองใช้โปรเจ็กต์ใหม่และ - แน่นอนว่ามันกลับมาKeyValuePairพร้อมคุณสมบัติKeyและValueความเป็น ทั้งคู่NULL.... เพื่อความปลอดภัยของคนอื่น 5 นาทีแห่งความโง่เขลานี้ ;-)
Nicolas

@Nicolas - ไม่มีความโง่ที่นี่ คุณควรตรวจสอบตัวเองและตรวจสอบให้แน่ใจว่าคุณเข้าใจรหัสของคุณอยู่เสมอ ฉันได้เพิ่มลิงก์ไปยังdefaultคีย์เวิร์ดแล้วมันหายไปอย่างชัดเจนที่นี่ ขอบคุณ!
Kobi

1
@JeffBridgman - นั่นเป็นจุดที่ดีจริงๆ! KeyValuePairโดยเฉพาะที่นี่มันเป็นไปไม่ได้เพราะเรากำลังทำงานกับ ถ้าคุณมีรหัสทั่วไปday.Equalsก็จะไม่ปลอดภัยและฉันจะใช้EqualityComparer<T>.Default.Equals(day, defaultDay)
Kobi

55

นี่เป็นวิธีที่ชัดเจนและรัดกุมที่สุดในความคิดของฉัน:

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

สิ่งนี้ใช้ประโยชน์ได้อย่างสมบูรณ์โดยใช้ค่าเริ่มต้นแปลก ๆ สำหรับโครงสร้าง


13
ปัญหาเกี่ยวกับสิ่งนี้คือมีความเป็นไปได้ (ขึ้นอยู่กับการนำไปใช้งาน) ที่วันที่นับได้จะถูกแจกแจงสองครั้งหรือแย่กว่านั้นคือส่งคืนค่าที่แตกต่างกันระหว่างการเรียก Any () และ First ()
Ray Booysen

@RayBooysen การเรียก ToArray หรือ ToList ช่วยแก้ปัญหาได้และคุณสามารถใช้ Count / Length และ Indexer ได้
คอนโซล

1
โปรดทราบว่าคำตอบของ @ Ray ใช้ไม่ได้ที่นี่เนื่องจากdaysเป็นไฟล์Dictionary<int,string>. จึงจะถือว่าเป็นIEnumerable<KeyValuePair<int,string>>แล้วมีพฤติกรรมตามที่คาดหวังเมื่อใดAny()และFirst()ถูกเรียก ฉันเดาว่ามีการใช้งานอื่น ๆ IEnumerable<>ที่สามารถทำงานแตกต่างกันเป็น ฉันไม่รู้ว่าฉันขาดอะไรไป
Emanuele Bellini

0

คุณสามารถทำสิ่งนี้แทนได้:

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

แล้ว:

if (day.Key == null) {
    System.Diagnotics.Debug.Write("Couldn't find day of week");
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.