Oto uproszczona wersja tego, co próbuję zrobić:
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));
Ponieważ „xyz” nie jest obecny w słowniku, metoda FirstOrDefault nie zwróci prawidłowej wartości. Chcę mieć możliwość sprawdzenia tej sytuacji, ale zdaję sobie sprawę, że nie mogę porównać wyniku z wartością „null”, ponieważ KeyValuePair jest strukturą. Poniższy kod jest nieprawidłowy:
if (day == null) {
System.Diagnotics.Debug.Write("Couldn't find day of week");
}
Podczas próby skompilowania kodu program Visual Studio zgłasza następujący błąd:
Operator '==' cannot be applied to operands of type 'System.Collections.Generic.KeyValuePair<int,string>' and '<null>'
Jak mogę sprawdzić, czy FirstOrDefault zwrócił prawidłową wartość?
Odpowiedzi:
FirstOrDefault
nie zwraca null, zwracadefault(T)
.Powinieneś sprawdzić:
var defaultDay = default(KeyValuePair<int, string>); bool b = day.Equals(defaultDay);
Z MSDN -
Enumerable.FirstOrDefault<TSource>
:Uwagi:
EqualityComparer<T>.Default.Equals(day, defaultDay)
, ponieważ.Equals
może zostać zastąpiony lubday
może to być pliknull
.KeyValuePair<int, string> defaultDay = default;
, zobacz literał „domyślny” z typem docelowym .FirstOrDefault
źródło
typeof
? Ten kod kompiluje się i działa.default(KeyValuePair<T1, T2>)
z tego wyniknie. Ok, powinno być dość oczywiste, że spowoduje to pusty KVP. Ale ponieważ "bycie oczywistym" nie jest dobrym podejściem do pisania poprawnych aplikacji (a moja obecna implementacja jest zbyt złożona, aby jasno / czysto sprowokować ten przypadek), wypróbowałem ją z nowym projektem i - rzeczywiście - zwróciłaKeyValuePair
z właściwościamiKey
iValue
byciem jedno i drugieNULL
... tylko po to, żeby uratować innym ludziom te 5 minut głupoty ;-)default
słowa kluczowego, którego tutaj wyraźnie brakuje. Dzięki!KeyValuePair
. Gdybyś miał ogólny kod,day.Equals
nie jest nawet bezpieczny dla null iEqualityComparer<T>.Default.Equals(day, defaultDay)
Moim zdaniem jest to najbardziej jasny i zwięzły sposób:
var matchedDays = days.Where(x => sampleText.Contains(x.Value)); if (!matchedDays.Any()) { // Nothing matched } else { // Get the first match var day = matchedDays.First(); }
To całkowicie rozwiązuje problem przy użyciu dziwnych wartości domyślnych dla struktur.
źródło
days
jestDictionary<int,string>
. Więc będzie traktowane jakoIEnumerable<KeyValuePair<int,string>>
, a następnie zachowuje się zgodnie z oczekiwaniami, gdyAny()
iFirst()
są wywoływane. Wydaje mi się, że istnieją inne implementacje, które mogą zachowywać się inaczej niżIEnumerable<>
. Nie wiem, czy czegoś mi brakuje.Zamiast tego możesz to zrobić:
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));
i wtedy :
if (day.Key == null) { System.Diagnotics.Debug.Write("Couldn't find day of week"); }
źródło