¿Cómo puedo detectar si esta clave de diccionario existe en C #?


498

Estoy trabajando con la API administrada de servicios web de Exchange, con datos de contacto. Tengo el siguiente código, que es funcional , pero no ideal:

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

Como dije, este código funciona . Ahora quiero hacer que apesta un poco menos , si es posible.

No puedo encontrar ningún método que me permita verificar la existencia de la clave en el diccionario antes de intentar acceder a ella, y si intento leerla (con .ToString()) y no existe, se produce una excepción:

500
La clave dada no estaba presente en el diccionario.

¿Cómo puedo refactorizar este código para absorber menos (sin dejar de ser funcional)?

Respuestas:


890

Puedes usar ContainsKey:

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

o TryGetValue:

dict.TryGetValue(key, out value);

Actualización : según un comentario, la clase real aquí no es un IDictionarysino un PhysicalAddressDictionary, por lo que los métodos son Containsy TryGetValuefuncionan de la misma manera.

Ejemplo de uso:

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

Actualización 2: aquí está el código de trabajo (compilado por el que hace la pregunta)

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

... con el condicional interno repetido según sea necesario para cada clave requerida. TryGetValue solo se realiza una vez por PhysicalAddressKey (Hogar, Trabajo, etc.).


El TryGetValueenfoque parece ser la mejor opción , ya que encontré esta página: goo.gl/7YN6 ... pero no estoy seguro de cómo usarla. En mi código anterior, rowes un 'objeto DataRow`, así que no estoy seguro de su código de ejemplo es correcta, aunque ...
— Adam Tuttle

¿Qué estoy haciendo mal aquí? c.PhysicalAddresses.TryGetValue(c.PhysicalAddresses[PhysicalAddressKey.Home].Street, row["HomeStreet"]);
— Adam Tuttle

1
@ Adam Tuttle: El segundo parámetro es un parámetro de salida. Intentaré adivinar el código que funciona y actualizaré mi respuesta, pero tendrás que perdonar los errores, ya que no puedo compilarlo aquí.
— Mark Byers

Buena respuesta. Para mantener la coherencia con SO, el término "preguntador" podría reemplazarse por "OP" (abreviatura de Cartel original).
— Lave Loos

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

12

¿De qué tipo es c.PhysicalAddresses? Si es así Dictionary<TKey,TValue>, puedes usar el ContainsKeymétodo.


Gracias, Adam, eso es realmente (no) útil. ¿Cuál es la jerarquía de clases? ¿Cuál es el tipo base?
— John Saunders


3

Utilizo un diccionario y debido a la repetitividad y las posibles teclas faltantes, rápidamente arreglé un pequeño método:

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

Llamándolo:

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

Hace el trabajo.


1

Aquí hay algo que cociné hoy. Parece funcionar para mi. Básicamente, usted anula el método Agregar en su espacio de nombres base para hacer una verificación y luego llama al método Agregar de la base para agregarlo realmente. Espero que esto funcione para usted

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());
        }
    }
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.