如何在C#中检测字典键是否存在?

630

我正在使用Exchange Web Services Managed API处理联系人数据。我有以下代码,它是可行的,但不是理想的:

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
给定的键在字典中不存在。

我该如何重构这段代码以使它更好(同时仍然保持其功能性)?

6个回答

1092

你可以使用ContainsKey


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

TryGetValue

dict.TryGetValue(key, out value);
更新: 根据评论,这里的实际类不是 IDictionary 而是一个 PhysicalAddressDictionary,因此方法是 ContainsTryGetValue,但它们的工作方式相同。

示例用法:

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

必要时为每个所需的键重复内部条件。对于每个物理地址键(Home、Work等),只执行一次TryGetValue操作。


“TryGetValue”方法似乎是最好的选择,因为我找到了这个页面:http://goo.gl/7YN6...但我不确定如何使用它。在我的上面的代码中,“row”是一个“DataRow”对象,所以我不确定你的示例代码是否正确... - Adam Tuttle
我在这里做错了什么?c.PhysicalAddresses.TryGetValue(c.PhysicalAddresses[PhysicalAddressKey.Home].Street, row["HomeStreet"]); - Adam Tuttle
1
@Adam Tuttle:第二个参数是一个输出参数。我会尝试猜测可行的代码并更新我的答案,但请原谅错误,因为我无法在这里编译它。 - Mark Byers
好的回答。为了在SO上保持一致,"question asker"这个术语可以被"OP"(原始发布者的缩写)所取代。 - Lave Loos
1
一行代码(需要 C# 7.0row["HomeStreet"] = c.PhysicalAddresses.TryGetValue(PhysicalAddressKey.Home, out PhysicalAddressEntry entry) ? entry.Street.ToString() : null; - Ivan García Topete

17

c.PhysicalAddresses的类型是什么?如果是Dictionary<TKey,TValue>,那么您可以使用ContainsKey方法。


谢谢,亚当,这真的(不)有帮助。类层次结构是什么?基础类型是什么? - John Saunders

7
我使用一个字典,由于重复和可能缺失的键,我迅速拼凑了一个小方法:
 private static string GetKey(IReadOnlyDictionary<string, string> dictValues, string keyValue)
 {
     return dictValues.ContainsKey(keyValue) ? dictValues[keyValue] : "";
 }

调用它:

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

完成任务。

6

3

以下是我今天编写的一些小东西。对我来说似乎挺有用的。基本上,您覆盖了基础命名空间中的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());
        }
    }
}

3

这是一个改进版的JohanE的答案,支持泛型并作为扩展方法:

public static TValue GetKey<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> dict, TKey key)
{
    return dict.ContainsKey(key) ? dict[key] : default;
}

调用它:

var entry = dict.GetKey("Key");

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接