Como posso ter certeza de que FirstOrDefault <KeyValuePair> retornou um valor


91

Esta é uma versão simplificada do que estou tentando fazer:

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

Como 'xyz' não está presente no dicionário, o método FirstOrDefault não retornará um valor válido. Quero ser capaz de verificar essa situação, mas percebo que não posso comparar o resultado com "null" porque KeyValuePair é uma estrutura. O seguinte código é inválido:

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

Quando você tenta compilar o código, o Visual Studio gera o seguinte erro:

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

Como posso verificar se FirstOrDefault retornou um valor válido?


1
Você tem um bug aí, mas presumo que seja uma coisa de copiar e colar: dias não é uma lista e você não pode usar o add em KeyValuePair.
Kobi

opa ... você está correto, eu estava digitando de memória e obviamente cometi um erro. Obrigado por apontar isso.
desautelsj

1
Provavelmente foi: var days = new Dictionary <int, string> ();
Even Mien

Respostas:


155

FirstOrDefaultnão retorna nulo, ele retorna default(T).
Você deve verificar:

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

Do MSDN -Enumerable.FirstOrDefault<TSource> :

padrão ( TSource ) se a fonte estiver vazia; caso contrário, o primeiro elemento na origem .

Notas:


16
+1, KeyValuePair é um tipo de valor (struct), não um tipo de referência (classe) ou um tipo de valor anulável, portanto, não pode ser nulo.
Lucas

6
@ paper1337 - Obrigado, mas onde estou perdendo typeof? Este código compila e funciona.
Kobi,

3
Vim aqui porque não estava claro para mim o default(KeyValuePair<T1, T2>)que resultaria. Ok, deveria ter sido bastante óbvio, que resultaria em um KVP vazio. Mas como "ser óbvio" não é uma boa abordagem para escrever aplicativos adequados (e minha implementação atual é muito complexa para provocar de forma clara / limpa este caso), eu tentei com um novo projeto e - de fato - ele retornou um KeyValuePaircom propriedades Keye Valuesendo ambos NULL.... apenas para proteger outras pessoas nestes 5 minutos de estupidez ;-)
Nicolas

@Nicolas - Sem estupidez aqui. É sempre uma boa ideia verificar por si mesmo e certificar-se de que entendeu seu código. Eu adicionei um link para a defaultpalavra-chave, ele está claramente faltando aqui. Obrigado!
Kobi

1
@JeffBridgman - Esse é realmente um bom ponto! Especificamente aqui não é possível, porque estamos trabalhando com KeyValuePair. Se você tivesse um código genérico, day.Equalsnem mesmo é seguro para nulos, e eu teria usadoEqualityComparer<T>.Default.Equals(day, defaultDay)
Kobi

53

Esta é a forma mais clara e concisa em minha opinião:

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

Isso contorna completamente o uso de coisas estranhas de valor padrão para estruturas.


13
O problema com isso é que existe a possibilidade (dependendo da implementação) de que os dias enumeráveis ​​sejam enumerados duas vezes ou, pior ainda, retornem valores diferentes entre as chamadas Any () e First ()
Ray Booysen

@RayBooysen Uma chamada de ToArray ou ToList resolve o problema e você pode usar Count / Length e um Indexer.
Console de

1
Observe que a resposta de @Ray não se aplica aqui, porque daysé a Dictionary<int,string>. Portanto, ele será considerado como um IEnumerable<KeyValuePair<int,string>>, comportando-se conforme o esperado quando Any()e First()for chamado. Eu acho que existem outras implementações que podem se comportar de forma diferente como IEnumerable<>. Não sei se estou perdendo alguma coisa.
Emanuele Bellini,

0

Você pode fazer isso:

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 depois :

if (day.Key == null) {
    System.Diagnotics.Debug.Write("Couldn't find day of week");
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.