相当于 Python 的 get() 方法的 C# 字典

C# Dictionary equivalent to Python's get() method

在 Python 中,如果我有一个字典,并且我想从一个可能不存在键的字典中获取一个值,我会做类似的事情:

lookupValue = somedict.get(someKey, someDefaultValue)

其中,如果 someKey 不存在,则返回 someDefaultValue

在 C# 中,TryGetValue() 有点类似:

var lookupValue;
if(!somedict.TryGetValue(someKey, lookupValue))
    lookupValue = someDefaultValue;

不过有一个问题是,如果 someKeynull,则会抛出一个异常,因此您要进行空检查:

var lookupValue = someDefaultValue;
if (someKey != null && !somedict.TryGetValue(someKey, lookupValue))
    lookupValue = someDefaultValue;

老实说,这很恶心(字典查找需要 3 行?)是否有更简洁(即 1 行)的方式很像 Python 的 get()

TryGetValue 不是您要查找的方法。此方法 returns 一个布尔值。如果找到密钥则为真,如果找到则为假 not.Anf 如果找到密钥,它将把值设置为您选择的变量。你要的方法,字典里没有class。 所以你有两个选择来解决这个问题:

  1. 检查是否存在:

    var value;
    if (somedic.TryGetValue("key", out value))
       lookupValue  = value;
    else
       lookupValue = defaultValue;
    
  2. 创建您自己的方法,如 blog 中所示。

下面是TryGetValue的正确使用方法。请注意,您不能在调用 TryGetValue 之前将 return 值设置为默认值,而只是 return 它,因为如果找不到密钥, TryGetValue 会将其重置为默认值.

public static TValue GetOrDefault<TKey, TValue>(
    this IDictionary<TKey, TValue> dictionary, 
    TKey key, 
    TValue defaultValue)
{
    TValue value;
    if(key == null || !dictionary.TryGetValue(key, out value))
        return defaultValue;
    return value;
}

当然,如果键是 null,您实际上可能想要一个例外,因为对于字典来说,这始终是无效键。

现在可以使用 C# 7.0 内联输出变量声明将其简化为以下内容。

return key ==  null || !dictionary.TryGetValue(key, out var value)
    ? defaultValue
    : value;

随着 C# 语言从 7.1 开始对 lambda 和默认值以及 8 对可空性进行了更多改进,Get() 函数现在可以写成

public static class Extentions
{
    /// <summary>
    /// Gets the value associated with the specified key.
    /// </summary>
    [return: NotNullIfNotNull("defaultValue")]
    public static TValue? Get<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, TValue? defaultValue = default)
      => key == null || !dictionary.TryGetValue(key, out var value) ? defaultValue : value;

    /// <summary>
    /// Gets the value associated with the specified key and box/un-box correctly.
    /// </summary>
    [return: NotNullIfNotNull("defaultValue")]
    public static TTarget? GetWithConversion<TTarget, TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, TTarget? defaultValue = default) where TTarget : TValue
      => (TTarget?)Convert.ChangeType(Get(dictionary, key, defaultValue), typeof(TTarget?), CultureInfo.InvariantCulture);
}

给出与重载 Python 等效项大致相同的行为。我也在使用 GetWithConversion 来处理对象 boxing/unboxing.

参考: => expression body, NotNullIfNotNull, default, Nullable reference types