NULL合并字典查找

时间:2019-03-19 22:30:42

标签: c# collections

经常困扰我的一件事是,执行此非常简单(对于我的工作,非常常见)的操作需要花费几行代码:

  var lTheDict = new Dictionary<string, object>();
  // The dictionary gets some stuff put in it elsewhere...

  // Do annoying lookup that must be common but is always unwieldy.
  object lTheObject;
  int lTheValue; // NOTE: Not always an int
  if (lTheDict.TryGetValue("TheKey", out lTheObject))
  {
    lTheValue = (int) lTheObject;
  }

我确信必须有更好的方法来执行此操作,也许可以使用null合并或其他方法。我真正想要写的东西是这样的:

  int lTheValue ?= (int) lTheDict["TheKey"];

换句话说,如果TheKey存在,请给我取值,否则请给我“空”整数。

几乎不可能刮掉线条。即使我们只是尝试查找并广播并在单行“捕获并忽略”中捕获异常(我的工作场所代码样式均不允许这样做),我们仍然必须 在try块外声明变量,并以类似以下内容结束:

  int lTheValue;
  try {
    lTheValue = (int) lTheDict["TheKey"];
  } catch (Exception ex) { }

这又是一个荒谬的开销代码,掩盖了应该是显而易见的操作。

即使只是能够摆脱lTheObject的声明,只要在我们将其用作outparam(在.NET 5或我听到的东西中使用它)时进行声明即可删除一行。这些函数本身的长度通常只有10行,并且看起来我们在对该集合进行一些重要的工作,因为一半的代码专用于获取值,但实际上这只是一种干扰。

注意::我知道我可以编写一个模板化函数来执行此操作,但是即使在该函数中,也不得不再次编写这些行。一定有更好的方法!

有没有人发现或者您能想到一种较短的书写方式?

2 个答案:

答案 0 :(得分:4)

static class MyExtensions
{
   public static T MagicGet<T>(
       this Dictionary<string, object> lookup,
       string key)
   {
       return lookup.TryGetValue(key, out var value)) ? (T)value : default(T);
   }
}
...
var value = lTheDict.MagicGet<int?>("TheKey");

或者不创建扩展名,您可以像这样简单地编写原始查询:

  int lTheValue = lTheDict.TryGetValue("TheKey", out object lTheObject) ? (int) lTheObject : default(int);

答案 1 :(得分:1)

我在大多数代码中都定义了这两种扩展方法:

public static Func<K, V> Map<K, V>(this IDictionary<K, V> source, Func<V> @default)
{
    return key => (key == null || !source.ContainsKey(key)) ? @default() : source[key];
}

public static Func<K, V> Map<K, V>(this IDictionary<K, V> source, Func<K, V> @default)
{
    return key => (key == null || !source.ContainsKey(key)) ? @default(key) : source[key];
}

然后您可以执行以下操作:

Dictionary<string, object> lTheDict = new Dictionary<string, object>();

Func<string, object> mapTheDict = lTheDict.Map(k => (int?)null);

object lTheValue = mapTheDict("TheKey");

这里有趣的是,您可以使用lambda返回基于键本身的默认值。我发现这非常有用-特别是对于调试。