Come posso rilevare se questa chiave del dizionario esiste in C #?


498

Sto lavorando con l'API gestita dei servizi Web di Exchange, con i dati di contatto. Ho il seguente codice, che è funzionale , ma non ideale:

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...
}

Come ho già detto, questo codice funziona . Ora voglio farlo succhiare un po 'meno , se possibile.

Non riesco a trovare alcun metodo che mi consenta di verificare l'esistenza della chiave nel dizionario prima di tentare di accedervi e se provo a leggerlo (con .ToString()) e non esiste, viene generata un'eccezione:

500
La chiave fornita non era presente nel dizionario.

Come posso refactoring questo codice per succhiare di meno (pur essendo ancora funzionale)?

Risposte:


890

Puoi usare ContainsKey:

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

oppure TryGetValue:

dict.TryGetValue(key, out value);

Aggiornamento : secondo un commento la classe attuale qui non è un IDictionaryma un PhysicalAddressDictionary, quindi i metodi sono Containse TryGetValuema funzionano allo stesso modo.

Esempio di utilizzo:

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

Aggiornamento 2: ecco il codice di lavoro (compilato dalla domanda richiedente)

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

... con il condizionale interno ripetuto come necessario per ogni chiave richiesta. TryGetValue viene eseguito una sola volta per PhysicalAddressKey (Casa, Lavoro, ecc.).


L' TryGetValueapproccio sembra essere la soluzione migliore, dato che ho trovato questa pagina: goo.gl/7YN6 ... ma non sono sicuro di come usarlo. Nel mio codice sopra, rowc'è un oggetto 'DataRow`, quindi non sono sicuro che il tuo codice di esempio sia giusto, però ...
Adam Tuttle,

Cosa sto sbagliando, qui? c.PhysicalAddresses.TryGetValue(c.PhysicalAddresses[PhysicalAddressKey.Home].Street, row["HomeStreet"]);
Adam Tuttle,

1
@Adam Tuttle: il secondo parametro è un parametro out. Proverò a indovinare il codice che funziona e ad aggiornare la mia risposta, ma dovrai perdonare gli errori perché non riesco a compilarlo qui.
Mark Byers,

Buona risposta. Per coerenza su SO, il termine "domanda frequente" potrebbe essere sostituito da "OP" (abbreviazione di Poster originale).
Lave Loos,

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

12

Di che tipo è c.PhysicalAddresses? In tal caso Dictionary<TKey,TValue>, è possibile utilizzare il ContainsKeymetodo


Grazie, Adam, è davvero (non) utile. Qual è la gerarchia di classi? Qual è il tipo di base?
John Saunders,


3

Uso un dizionario e, a causa della ripetitività e delle possibili chiavi mancanti, ho rapidamente messo insieme un piccolo metodo:

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

Chiamandolo:

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

Completa il lavoro.


1

Ecco qualcosa che ho preparato oggi. Sembra funzionare per me. Fondamentalmente si sovrascrive il metodo Aggiungi nel proprio spazio dei nomi di base per fare un controllo e quindi si chiama il metodo Aggiungi della base per aggiungerlo effettivamente. Spero che questo funzioni per te

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());
        }
    }
}
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.