NULL коалесцирующий диктонический поиск - PullRequest
2 голосов
/ 20 марта 2019

Меня всегда беспокоит то, сколько строк кода требуется для выполнения этой очень простой (и для моей работы, очень распространенной) операции:

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

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

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

Другими словами, если TheKey существует, получите мне значение, в противном случае просто дайте мне «пустое» int.

Почти невозможно сбрить линии.Даже если мы просто попытаемся выполнить поиск и приведение и поймать исключение в одной строке «поймай и проигнорируй» (ни один из которых не разрешен моим стилем кода на рабочем месте), мы все же должны объявитьпеременная вне блока try, и в результате получается что-то вроде:

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

Это опять-таки нелепое количество служебного кода, маскирующего то, что должно быть довольно очевидной операцией.

Даже просто длябыть в состоянии избавиться от объявления lTheObject, объявив его в точке, где мы используем его в качестве outparam (который входит в .NET 5 или что-то, что я слышу), удалит одну строку.Функции, в которых они существуют, часто сами по себе содержат всего 10 строк, и похоже, что мы делаем что-то важное с этой коллекцией, потому что половина кода посвящена просто получению значения, но на самом деле это просто отвлечение внимания.

ПРИМЕЧАНИЕ: Я знаю, что могу написать шаблонную функцию для этого, но даже в функции это будет раздражать меня от необходимости писать эти строки СНОВА.Должен быть лучший способ!

Кто-нибудь нашел или вы можете придумать более короткий способ написать это?

Ответы [ 2 ]

4 голосов
/ 20 марта 2019
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 голос
/ 20 марта 2019

У меня есть два метода расширения, определенных в большей части моего кода:

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");

Интересно то, что вы можете использовать лямбду для возврата значения по умолчанию, основанного на самом ключе. Я нахожу это очень полезным - особенно для отладки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...