Come posso assicurarmi che FirstOrDefault <KeyValuePair> abbia restituito un valore


91

Ecco una versione semplificata di quello che sto cercando di fare:

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

Poiché "xyz" non è presente nel dizionario, il metodo FirstOrDefault non restituirà un valore valido. Voglio essere in grado di verificare questa situazione, ma mi rendo conto che non posso confrontare il risultato con "null" perché KeyValuePair è una struttura. Il codice seguente non è valido:

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

Quando si tenta di compilare il codice, Visual Studio genera il seguente errore:

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

Come posso verificare che FirstOrDefault abbia restituito un valore valido?


1
Hai un bug lì, ma presumo sia una cosa copia-incolla: i giorni non sono un elenco e non puoi usare add su KeyValuePair.
Kobi

ooops ... hai ragione stavo scrivendo a memoria e ovviamente ho fatto un errore. Grazie per segnalarlo.
desautelsj

1
Probabilmente era: var days = new Dictionary <int, string> ();
Anche Mien

Risposte:


155

FirstOrDefaultnon restituisce null, restituisce default(T).
Dovresti controllare:

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

Da MSDN -Enumerable.FirstOrDefault<TSource> :

default ( TSource ) se la sorgente è vuota; altrimenti, il primo elemento in source .

Appunti:


16
+1, KeyValuePair è un tipo di valore (struct), non un tipo di riferimento (classe) o un tipo di valore nullable, quindi non può essere null.
Lucas

6
@ paper1337 - Grazie, ma dove mi manca typeof? Questo codice si compila e funziona.
Kobi

3
Sono venuto qui perché non mi era chiaro quale default(KeyValuePair<T1, T2>)sarebbe stato il risultato. Ok, avrebbe dovuto essere abbastanza ovvio, che avrebbe prodotto un KVP vuoto. Ma poiché "essere ovvio" non è un buon approccio per scrivere applicazioni corrette (e la mia attuale implementazione è troppo complessa per provocare chiaramente / in modo pulito questo caso), l'ho provato con un nuovo progetto e - in effetti - ha restituito una KeyValuePaircon proprietà Keyed Valueessendo entrambi NULL.... giusto per mettere al sicuro altre persone questi 5 minuti di stupidità ;-)
Nicolas

@Nicolas - Nessuna stupidità qui. È sempre una buona idea controllare di persona e assicurarsi di aver compreso il codice. Ho aggiunto un collegamento alla defaultparola chiave, chiaramente manca qui. Grazie!
Kobi

1
@ JeffBridgman - Questo è davvero un buon punto! In particolare qui non è possibile, perché stiamo lavorando con KeyValuePair. Se avessi un codice generico, day.Equalsnon è nemmeno null-safe e avrei usatoEqualityComparer<T>.Default.Equals(day, defaultDay)
Kobi

53

Questo è il modo più chiaro e conciso secondo me:

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

Questo aggira completamente usando strani valori predefiniti per gli struct.


13
Il problema con questo, è che esiste la possibilità (a seconda dell'implementazione) che i giorni enumerabili vengano enumerati due volte o, peggio ancora, restituiscano valori diversi tra le chiamate Any () e First ()
Ray Booysen

@RayBooysen Una chiamata a ToArray o ToList risolve il problema e puoi usare Count / Length e un Indexer.
Console

1
Nota che la risposta di @ Ray non si applica qui, perché daysè un file Dictionary<int,string>. Quindi verrà considerato come un IEnumerable<KeyValuePair<int,string>>, quindi si comporterà come previsto quando Any()e First()verranno chiamati. Immagino che ci siano altre implementazioni che possono comportarsi in modo diverso come IEnumerable<>. Non so se mi sto perdendo qualcosa.
Emanuele Bellini

0

Puoi farlo invece:

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

e poi :

if (day.Key == null) {
    System.Diagnotics.Debug.Write("Couldn't find day of week");
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.