Comment puis-je détecter si cette clé de dictionnaire existe en C #?


498

Je travaille avec l'API gérée des services Web Exchange, avec les données de contact. J'ai le code suivant, qui est fonctionnel , mais pas idéal:

foreach (Contact c in contactList)
{
    string openItemUrl = "https://" + service.Url.Host + "/owa/" + c.WebClientReadFormQueryString;

    row = table.NewRow();
    row["FileAs"] = c.FileAs;
    row["GivenName"] = c.GivenName;
    row["Surname"] = c.Surname;
    row["CompanyName"] = c.CompanyName;
    row["Link"] = openItemUrl;

    //home address
    try { row["HomeStreet"] = c.PhysicalAddresses[PhysicalAddressKey.Home].Street.ToString(); }
    catch (Exception e) { }
    try { row["HomeCity"] = c.PhysicalAddresses[PhysicalAddressKey.Home].City.ToString(); }
    catch (Exception e) { }
    try { row["HomeState"] = c.PhysicalAddresses[PhysicalAddressKey.Home].State.ToString(); }
    catch (Exception e) { }
    try { row["HomeZip"] = c.PhysicalAddresses[PhysicalAddressKey.Home].PostalCode.ToString(); }
    catch (Exception e) { }
    try { row["HomeCountry"] = c.PhysicalAddresses[PhysicalAddressKey.Home].CountryOrRegion.ToString(); }
    catch (Exception e) { }

    //and so on for all kinds of other contact-related fields...
}

Comme je l'ai dit, ce code fonctionne . Maintenant, je veux le faire sucer un peu moins , si possible.

Je ne trouve aucune méthode qui me permette de vérifier l'existence de la clé dans le dictionnaire avant d'essayer d'y accéder, et si j'essaie de la lire (avec .ToString()) et qu'elle n'existe pas, une exception est levée:

500
La clé donnée n'était pas présente dans le dictionnaire.

Comment puis-je refactoriser ce code pour aspirer moins (tout en étant fonctionnel)?

Réponses:


890

Vous pouvez utiliser ContainsKey:

if (dict.ContainsKey(key)) { ... }

ou TryGetValue:

dict.TryGetValue(key, out value);

Mise à jour : selon un commentaire, la classe réelle ici n'est pas un IDictionarymais un PhysicalAddressDictionary, donc les méthodes sont ContainsetTryGetValue mais elles fonctionnent de la même manière.

Exemple d'utilisation:

PhysicalAddressEntry entry;
PhysicalAddressKey key = c.PhysicalAddresses[PhysicalAddressKey.Home].Street;
if (c.PhysicalAddresses.TryGetValue(key, out entry))
{
    row["HomeStreet"] = entry;
}

Mise à jour 2: voici le code de travail (compilé par le demandeur de questions)

PhysicalAddressEntry entry;
PhysicalAddressKey key = PhysicalAddressKey.Home;
if (c.PhysicalAddresses.TryGetValue(key, out entry))
{
    if (entry.Street != null)
    {
        row["HomeStreet"] = entry.Street.ToString();
    }
}

... avec le conditionnel intérieur répété si nécessaire pour chaque clé requise. TryGetValue n'est effectué qu'une seule fois par PhysicalAddressKey (domicile, travail, etc.).


L' TryGetValueapproche semble être la meilleure solution, car j'ai trouvé cette page: goo.gl/7YN6 ... mais je ne sais pas comment l'utiliser. Dans mon code ci-dessus, rowest un objet 'DataRow`, donc je ne suis pas sûr que votre exemple de code soit correct, cependant ...
Adam Tuttle

Qu'est-ce que je fais mal ici? c.PhysicalAddresses.TryGetValue(c.PhysicalAddresses[PhysicalAddressKey.Home].Street, row["HomeStreet"]);
Adam Tuttle

1
@Adam Tuttle: Le deuxième paramètre est un paramètre de sortie. Je vais essayer de deviner le code qui fonctionne et mettre à jour ma réponse, mais vous devrez pardonner les erreurs car je ne peux pas le compiler ici.
Mark Byers

Bonne réponse. Pour des raisons de cohérence sur SO, le terme «poseur de questions» pourrait être remplacé par «OP» (abréviation de affiche originale).
Lave Loos du

Un paquebot (obligatoire C# 7.0)row["HomeStreet"] = c.PhysicalAddresses.TryGetValue(PhysicalAddressKey.Home, out PhysicalAddressEntry entry) ? entry.Street.ToString() : null;
Ivan García Topete

12

Quel est le type de c.PhysicalAddresses? Si c'est le cas Dictionary<TKey,TValue>, vous pouvez utiliser la ContainsKeyméthode.


Merci, Adam, c'est vraiment (pas) utile. Quelle est la hiérarchie des classes? Quel est le type de base?
John Saunders


3

J'utilise un dictionnaire et en raison de la répétitivité et des clés manquantes possibles, j'ai rapidement corrigé une petite méthode:

 private static string GetKey(IReadOnlyDictionary<string, string> dictValues, string keyValue)
 {
     return dictValues.ContainsKey(keyValue) ? dictValues[keyValue] : "";
 }

L'appeler:

var entry = GetKey(dictList,"KeyValue1");

Obtient le travail.


1

Voici un petit quelque chose que j'ai concocté aujourd'hui. Semble fonctionner pour moi. Fondamentalement, vous remplacez la méthode Add dans votre espace de noms de base pour effectuer une vérification, puis appelez la méthode Add de la base pour l'ajouter réellement. J'espère que cela fonctionne pour toi

using System;
using System.Collections.Generic;
using System.Collections;

namespace Main
{
    internal partial class Dictionary<TKey, TValue> : System.Collections.Generic.Dictionary<TKey, TValue>
    {
        internal new virtual void Add(TKey key, TValue value)
        {   
            if (!base.ContainsKey(key))
            {
                base.Add(key, value);
            }
        }
    }

    internal partial class List<T> : System.Collections.Generic.List<T>
    {
        internal new virtual void Add(T item)
        {
            if (!base.Contains(item))
            {
                base.Add(item);
            }
        }
    }

    public class Program
    {
        public static void Main()
        {
            Dictionary<int, string> dic = new Dictionary<int, string>();
            dic.Add(1,"b");
            dic.Add(1,"a");
            dic.Add(2,"c");
            dic.Add(1, "b");
            dic.Add(1, "a");
            dic.Add(2, "c");

            string val = "";
            dic.TryGetValue(1, out val);

            Console.WriteLine(val);
            Console.WriteLine(dic.Count.ToString());


            List<string> lst = new List<string>();
            lst.Add("b");
            lst.Add("a");
            lst.Add("c");
            lst.Add("b");
            lst.Add("a");
            lst.Add("c");

            Console.WriteLine(lst[2]);
            Console.WriteLine(lst.Count.ToString());
        }
    }
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.