Как я могу сделать этот код TryGetValue словаря более читабельным? - PullRequest
6 голосов
/ 10 июня 2010

Я хотел бы проверить, был ли идентификатор еще не известен или, если он известен, изменилось ли связанное значение. В настоящее время я использую код, подобный этому, но это трудно понять тем, кто не знаком с шаблоном. Можете ли вы придумать способ сделать его более читабельным, оставляя его коротким в LOC?

string id;
string actual;
string stored;

if (!someDictionary.TryGetValue (id, out stored) || stored != actual) {
    // id not known yet or associated value changed.
}

Ответы [ 10 ]

5 голосов
/ 10 июня 2010

Вы можете написать метод расширения с хорошим именем:

public static class Utility
{
    public static bool ValueChangedOrUnknown(this Dictionary<string, string> dictionary, string id, string actual)
    {
        string stored = null;
        return (!dictionary.TryGetValue(id, out actual) || stored != actual);
    }
}

, чтобы позже вы могли использовать

string id;
string actual;

if (someDictionary.ValueChangedOrUnknown(id, actual) {
    // id not known yet or associated value changed.
}
4 голосов
/ 10 июня 2010

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

bool isKnown = someDictionary.TryGetValue (id, out stored);
// can only change when it is known
bool valueChanged = isKnown && stored != actual;

// quite self-explanatory, isn't it?
if (!isKnown || valueChanged) 
{

}
3 голосов
/ 10 июня 2010

завернуть каждую часть ||в свой собственный метод или свойство, чем вы можете написать это так:

if ( IdIsNew() || IdChanged())
2 голосов
/ 10 июня 2010

Двойственность.

if (!(someDictionary.TryGetValue (id, out stored) && stored == actual)) ...

Не уверен, что он более читабельный, хотя ... но это полезно знать.

1 голос
/ 10 июня 2010

Это выглядит хорошо для меня ... читается так же просто, как любое другое условие if.Единственное, что я мог бы изменить, это перебросить отрицания по поводу досрочного выхода:

if (someDictionary.TryGetValue(id, out stored) && stored == actual) {
    return;
}
// store new value

Я не вижу в этом никакой путаницы, никогда не думал, что это особенно неприятная идиомаи смиренно предполагаю, что те разработчики C #, которые были смущены этим, привыкли к этому.Это обычное дело, лаконично, и дает столько LOC, сколько заслуживает.Превращение его в 10 строк кода делает его way слишком важным.

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

1 голос
/ 10 июня 2010

Я бы предпочел новый метод:

public bool ShouldSetValue(Dictionary someDictionary, object id,object actualValue)
{
    string stored;

    if (someDictionary.TryGetValue (id, out stored)) 
    {
        if (stored != actualValue)
            return true;
    }
    else
    {
        return true;
    }
}

, тогда в существующем методе я бы просто:

if (ShouldSetValue(someDictionary,id,actual))
{
     someDictionary[id]=actual;
}
0 голосов
/ 30 июня 2010

Хотя я признаю, что шаблон «try» необходим, я не люблю реализации, для которых требуется параметр «out».Было бы намного полезнее иметь функции, подобные TryGetValue:

  • TryGetDictValue (словарь, ключ) возвращает ноль, если ключ отсутствует в словаре
  • TryGetDictValue (словарь, ключ, defaultValue) возвращаетdefaultValue, если ключ отсутствует в словаре
  • TryGetDictValue (словарь, ключ, valueReturningDelegate) вызывает предоставленный делегат, если ключ отсутствует в словаре, и возвращает его результат

В каждом случае возвращаемое значениетип результата - тип словаря.

Жаль, что нет способа проникнуть в машину времени и сделать такие вещи методами словаря.С другой стороны, их можно реализовать как статические функции, используя словарь в качестве первого параметра.

0 голосов
/ 10 июня 2010
public T GetValue(int id, object actual)
{
  object stored;
 if (someDictionary.TryGetValue (id, out stored) || stored == actual) 
    return stored;
  return new object();
}
0 голосов
/ 10 июня 2010

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

public static class DictionaryExtensions
{
    public static DictionaryChecker<TKey,TValue> contains<TKey,TValue>(this IDictionary<TKey,TValue> dictionary, TValue value)
    {
        return new DictionaryChecker<TKey,TValue>(value, dictionary);
    }
}

public class DictionaryChecker<TKey,TValue>
{
    TValue value;
    IDictionary<TKey,TValue> dictionary;

    internal DictionaryChecker(TValue value, IDictionary<TKey, TValue> dictionary)
    {
        this.value = value;
        this.dictionary = dictionary;
    }

    public bool For(TKey key)
    {
        TValue result;
        return dictionary.TryGetValue(key, out result) && result.Equals(value);
    }
}

Теперь замените код на:

if(!someDictionary.contains(actual).For(id)){
    // id not known yet or associated value changed.
}
0 голосов
/ 10 июня 2010

Метод расширения будет гладким:

public static class DictionaryExtensions
{
    public static bool ShouldAddValue<TKey, TValue>(this Dictionary<TKey, TValue> someDictionary, TKey id, TValue actual)
    {
        TValue stored;
        return (!someDictionary.TryGetValue(id, out stored) || !stored.Equals(actual)); 
    }
}

Использование:

someDictionary.ShouldAddValue("foo", "bar")
...