Как я могу убедиться, что 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 вернул допустимое значение?

Desautelsj
источник
1
У вас есть ошибка, но я предполагаю, что это копипаст: дни - это не список, и вы не можете использовать добавление в KeyValuePair.
Коби
упс ... вы правы, я печатал по памяти и явно ошибся. Спасибо, что указали на это.
desautelsj
1
Вероятно, это было: var days = new Dictionary <int, string> ();
Even Mien

Ответы:

156

FirstOrDefaultне возвращает null, он возвращается default(T).
Вы должны проверить:

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

Из MSDN -Enumerable.FirstOrDefault<TSource> :

по умолчанию ( TSource ), если источник пуст; в противном случае - первый элемент в источнике .

Примечания:

Коби
источник
17
+1, KeyValuePair - это тип значения (структура), а не ссылочный тип (класс) или тип значения, допускающий значение NULL, поэтому он не может быть нулевым.
Лукас,
6
@ paper1337 - Спасибо, а где я пропал typeof? Этот код компилируется и работает.
Коби
3
Я пришел сюда, потому что мне было непонятно, к чему default(KeyValuePair<T1, T2>)это приведет. Хорошо, должно было быть совершенно очевидно, что это приведет к пустому KVP. Но «не очевидно» не хороший подход писать собственные приложения (и моя текущая реализация слишком сложна , чтобы ясно / чисто спровоцировать этот случай), я попробовал его с новым проектом и - на самом деле - он вернулся KeyValuePairсо свойствами Keyи Valueсущества и то и другое NULL.... просто чтобы уберечь других людей эти 5 минут глупости ;-)
Николас
@Nicolas - Никакой глупости. Всегда полезно проверить себя и убедиться, что вы понимаете свой код. Я добавил ссылку на defaultключевое слово, здесь ее явно не хватает. Благодарность!
Коби
1
@JeffBridgman - Это действительно хороший аргумент! Конкретно здесь это невозможно, потому что мы работаем с KeyValuePair. Если бы у вас был общий код, day.Equalsон даже не является нулевым, и я бы использовалEqualityComparer<T>.Default.Equals(day, defaultDay)
Коби
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 ()
Рэй Буйсен,
@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");
}
Джоселин Маркотт
источник