Как я могу определить, существует ли этот ключ словаря в C #?

Я работаю с управляемым API веб-служб Exchange с контактными данными. У меня есть следующий код, который является функциональным, но не идеальным:

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

Как я уже сказал, этот код работает. Теперь я хочу, чтобы это было отстойным немного меньше, если это возможно.

Я не могу найти никаких методов, которые позволяют мне проверить наличие ключа в словаре, прежде чем пытаться получить к нему доступ, и если я попытаюсь прочитать его (с .ToString()), а он не существует, выдается исключение:

500
Данный ключ отсутствует в словаре.

Как я могу реорганизовать этот код, чтобы он был меньше отстойного (оставаясь при этом работоспособным)?


person Adam Tuttle    schedule 13.05.2010    source источник


Ответы (5)


Вы можете использовать ContainsKey:

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

или TryGetValue:

dict.TryGetValue(key, out value);

Обновление: согласно комментарию фактический класс здесь не IDictionary, а _ 6_, поэтому методы: _ 7_ и _ 8_, но они работают одинаково.

Пример использования:

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

Обновление 2: вот рабочий код (скомпилированный тем, кто задает вопрос)

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

... с повторением внутреннего условного выражения по мере необходимости для каждого требуемого ключа. TryGetValue выполняется только один раз для PhysicalAddressKey (домашний, рабочий и т. Д.).

person Mark Byers    schedule 13.05.2010
comment
Подход TryGetValue кажется лучшим вариантом, поскольку я нашел эту страницу: goo.gl/7YN6. .. но я не знаю, как им пользоваться. В моем приведенном выше коде row - это объект DataRow, поэтому я не уверен, что ваш пример кода верен ... - person Adam Tuttle; 14.05.2010
comment
Что я здесь делаю не так? c.PhysicalAddresses.TryGetValue(c.PhysicalAddresses[PhysicalAddressKey.Home].Street, row["HomeStreet"]); - person Adam Tuttle; 14.05.2010
comment
@Adam Tuttle: Второй параметр - это выходной параметр. Я попытаюсь угадать, какой код работает, и обновлю свой ответ, но вам придется простить ошибки, так как я не могу его здесь скомпилировать. - person Mark Byers; 14.05.2010
comment
Хороший ответ. Для единообразия SO термин задающий вопрос можно заменить на OP (сокращение от Original Poster). - person Lave Loos; 15.08.2015
comment
Один вкладыш (требуется C# 7.0) row["HomeStreet"] = c.PhysicalAddresses.TryGetValue(PhysicalAddressKey.Home, out PhysicalAddressEntry entry) ? entry.Street.ToString() : null; - person Ivan García Topete; 19.12.2018

Какой тип c.PhysicalAddresses? Если это Dictionary<TKey,TValue>, вы можете использовать метод ContainsKey.

person John Saunders    schedule 13.05.2010
comment
Спасибо, Адам, это действительно (не) полезно. Какая иерархия классов? Какой базовый тип? - person John Saunders; 14.05.2010

PhysicalAddressDictionary.TryGetValue

 public bool TryGetValue (
    PhysicalAddressKey key,
    out PhysicalAddressEntry physicalAddress
     )
person David Neale    schedule 13.05.2010

Я использую словарь, и из-за повторяемости и возможных отсутствующих ключей я быстро собрал небольшой метод:

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

Называя это:

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

Выполняет свою работу.

person JohanE    schedule 17.09.2018

Вот кое-что, что я приготовил сегодня. Кажется, у меня работает. В основном вы переопределяете метод Add в своем базовом пространстве имен, чтобы выполнить проверку, а затем вызываете базовый метод Add, чтобы фактически добавить его. Надеюсь, что это работает для вас

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());
        }
    }
}
person xul8tr    schedule 31.07.2018