Як я можу переконатися, що 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 не поверне дійсного значення. Я хочу мати можливість перевірити цю ситуацію, але я усвідомлюю, що не можу порівняти результат із "нулем", оскільки 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
У вас там помилка, але я припускаю, що це копіювати-вставити: дні не є списком, і ви не можете використовувати add на KeyValuePair.
Кобі

ой-ой ... ви праві, я набирав текст з пам'яті і явно помилився. Дякуємо, що вказали на це.
desautelsj

1
Ймовірно, це було: var days = new Dictionary <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), а не посилальним типом (класом) або типом значення, що може обнулятися, тому він не може бути нульовим.
Лукас

6
@ paper1337 - Дякую, але де я пропав typeof? Цей код компілюється та працює.
Кобі

3
Я прийшов сюди, бо мені було незрозуміло, до чого default(KeyValuePair<T1, T2>)це призведе. Добре, це мало бути цілком очевидно, що це призведе до порожнього KVP. Але «не очевидно" не хороший підхід писати власні програми (і моя поточна реалізація занадто складна , щоб ясно / чисто спровокувати цей випадок), я спробував його з новим проектом і - на самому ділі - він повернувся KeyValuePairз властивостями Keyі Valueістоти обидва NULL.... просто для того, щоб захистити деяких інших людей цих 5 хвилин дурості ;-)
Ніколас

@ Ніколас - Ніякої дурості тут. Завжди корисно перевірити самостійно та переконатися, що розумієте свій код. Я додав посилання на defaultключове слово, воно тут явно відсутнє. Дякую!
Кобі

1
@JeffBridgman - Це справді хороший момент! Конкретно тут це неможливо, тому що ми працюємо з KeyValuePair. Якби у вас був загальний код, day.Equalsвін навіть не є нульовим, і я б його використавEqualityComparer<T>.Default.Equals(day, defaultDay)
Кобі

54

На мій погляд, це найбільш чіткий і стислий спосіб:

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<>. Не знаю, чи мені чогось не вистачає.
Емануеле Белліні,

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");
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.