web-dev-qa-db-fra.com

Dictionary.FirstOrDefault () comment déterminer si un résultat a été trouvé

J'ai (ou voulais avoir) un code comme celui-ci:

IDictionary<string,int> dict = new Dictionary<string,int>();
// ... Add some stuff to the dictionary.

// Try to find an entry by value (if multiple, don't care which one).
var entry = dict.FirstOrDefault(e => e.Value == 1);
if ( entry != null ) { 
   // ^^^ above gives a compile error:
   // Operator '!=' cannot be applied to operands of type 'System.Collections.Generic.KeyValuePair<string,int>' and '<null>'
}

J'ai aussi essayé de changer la ligne incriminée comme ceci:

if ( entry != default(KeyValuePair<string,int>) ) 

Mais cela donne aussi une erreur de compilation:

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

Qu'est-ce qui donne ici? 

39
Eric Petroelje

La réponse de Jon fonctionnera avec Dictionary<string, int>, car cela ne peut pas avoir une valeur de clé nulle dans le dictionnaire. Cela ne fonctionnerait pas avec Dictionary<int, string>, cependant, car cela ne représente pas une valeur de clé nulle ... le mode "échec" se retrouverait avec une clé de 0.

Deux options:

Ecrivez une méthode TryFirstOrDefault, comme ceci:

public static bool TryFirstOrDefault<T>(this IEnumerable<T> source, out T value)
{
    value = default(T);
    using (var iterator = source.GetEnumerator())
    {
        if (iterator.MoveNext())
        {
            value = iterator.Current;
            return true;
        }
        return false;
    }
}

Sinon, projetez sur un type nullable:

var entry = dict.Where(e => e.Value == 1)
                .Select(e => (KeyValuePair<string,int>?) e)
                .FirstOrDefault();

if (entry != null)
{
    // Use entry.Value, which is the KeyValuePair<string,int>
}
39
Jon Skeet

Faites-le de cette façon:

if ( entry.Key != null )

Le fait est que la méthode FirstOrDefault renvoie un KeyValuePair<string, int> qui est un type value, de sorte qu'il ne peut jamais être null. Vous devez déterminer si une valeur a été trouvée en vérifiant si au moins une de ses propriétés Key, Value a sa valeur par défaut. Key est de type string, il est donc judicieux de vérifier que pour null, étant donné que le dictionnaire ne peut pas contenir d'élément avec une clé null.

Autres approches que vous pourriez utiliser:

var entry = dict.Where(e => e.Value == 1)
                .Select(p => (int?)p.Value)
                .FirstOrDefault();

Cela projette les résultats dans une collection d’entiers annulables, et si elle est vide (pas de résultats), vous obtenez une valeur nulle. Il n’est pas possible de confondre cela avec la int qu’une recherche fructueuse donnerait.

36
Jon

Quels que soient les types de clé et de valeur, vous pouvez procéder comme suit:

    static void Main(string[] args)
    {
        var dict = new Dictionary<int, string>
        {
            {3, "ABC"},
            {7, "HHDHHGKD"}
        };

        bool found = false;
        var entry = dict.FirstOrDefault(d => d.Key == 3 && (found=true));
        if (found)
        {
            Console.WriteLine("found: " + entry.Value);
        }
        else
        {
            Console.WriteLine("not found");
        }
        Console.ReadLine();
    }
5
Emerson Cardoso
public static TValue FirstOrDefault<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, Func<KeyValuePair<TKey, TValue>, bool> where)
    {
        foreach (var kv in dictionary)
        {
            if (where(kv))
                return kv.Value;
        }
        return default;
    }
0
Smagin Alexey