Как я могу сделать этот Словарь, который TryGetValue кодируют более читаемый?

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

string id;
string actual;
string stored;

if (!someDictionary.TryGetValue (id, out stored) || stored != actual) {
    // id not known yet or associated value changed.
}
6
задан mafu 10 June 2010 в 13:20
поделиться

10 ответов

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

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

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

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

1
ответ дан 8 December 2019 в 14:40
поделиться

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

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.
}
5
ответ дан 8 December 2019 в 14:40
поделиться

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

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) 
{

}
4
ответ дан 8 December 2019 в 14:40
поделиться

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

if ( IdIsNew() || IdChanged())
3
ответ дан 8 December 2019 в 14:40
поделиться

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

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

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

2
ответ дан 8 December 2019 в 14:40
поделиться

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

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;
}
1
ответ дан 8 December 2019 в 14:40
поделиться

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

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
ответ дан 8 December 2019 в 14:40
поделиться
public T GetValue(int id, object actual)
{
  object stored;
 if (someDictionary.TryGetValue (id, out stored) || stored == actual) 
    return stored;
  return new object();
}
0
ответ дан 8 December 2019 в 14:40
поделиться

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

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")
0
ответ дан 8 December 2019 в 14:40
поделиться

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

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

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

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

0
ответ дан 8 December 2019 в 14:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: