Свойство KeyValuePair‹TKey, Tvalue›.Value не имеет установщика

Я использую Dictionary<int, KeyValuePair<bool, int>> для хранения данных.

Время от времени мне нужно увеличить int в KeyValuePair, но это не позволит мне, потому что у него нет сеттера. Есть ли способ увеличить его?

Пример кода:

Dictionary<int, KeyValuePair<bool, int>> mDictionary = 
    new Dictionary<int, KeyValuePair<bool, int>>();

mDictionary[trapType].Value++;
//Error: The property KeyValuePair<TKey, Tvalue>>.Value has no setter

person choppy    schedule 14.05.2012    source источник


Ответы (6)


Есть ли способ увеличить его?

Нет. KeyValuePair является неизменяемым — это также тип значения, поэтому изменение значения свойства Value после создания копии в любом случае не поможет.

Вы должны были бы написать что-то вроде этого:

var existingValue = mDictionary[trapType];
var newValue = new KeyValuePair<bool, int>(existingValue.Key,
                                           existingValue.Value + 1);
mDictionary[trapType] = newValue;

Однако это довольно уродливо — вам действительно нужно, чтобы значение было KeyValuePair?

person Jon Skeet    schedule 14.05.2012
comment
Я бы предложил Tuple. Кратчайшим способом его создания будет Tuple.Create(existingValue.Key, existingValue.Value + 1). Хотя при создании класса, если это логично, было бы лучше избегать ненужных new(). - person SimpleVar; 14.05.2012
comment
@YoryeNathan: Да, это, вероятно, было бы уместно - или отдельный тип с именами свойств, которые отражают реальные значения bool и int. (Я вижу, вы тоже отредактировали свой комментарий :) - person Jon Skeet; 14.05.2012
comment
Да, хотя я могу представить себе случаи, когда это будет использоваться в небольшом объеме для какого-то причудливого алгоритма, и в этом случае я бы лично предпочел анонимный тип. - person SimpleVar; 14.05.2012

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

person Tim Rogers    schedule 14.05.2012

другое решение - создать новый словарь и передать ему новые значения и ключи:

foreach (var d in existingDic)
                    newDic.Add(d.Key, d.Value + 1);
person mashta gidi    schedule 19.06.2012

Концептуально KeyValuePair<TKey,TValue> — это просто пара переменных, Key и Value. Если бы Microsoft реализовала его с открытыми общедоступными полями Key и Value, его семантика была бы идеальной; при использовании в качестве управляющей переменной ForEach она была бы неизменной, но можно было бы обновить поле ключа или значения обычной переменной или элемента массива без необходимости обновления другого.

К сожалению, Microsoft, похоже, не желает, чтобы типы фреймворков выставляли какие-либо общедоступные поля, даже для таких типов, как KeyValuePair<TKey,TValue> или Drawing.Rectangle, семантика которых диктует, что (1) тип должен быть структурой; (2) все его состояние видно в фиксированном наборе свойств (могут быть и другие вычисляемые свойства помимо тех, которые определяют состояние объекта), и (3) этим свойствам может быть присвоена любая комбинация значений, подходящая для их типов. Следовательно, Microsoft рассматривала возможность предоставления членов, составляющих состояние типов, только как свойства, доступные только для чтения, или как свойства для чтения и записи. Использование свойств чтения-записи будет означать, что такой код:

for each (var item in myDictionary)
    item.Value += 1;

or

...assuming MyList is a List<Drawing.Rectangle>
MyList[3].Width += 9;

будет интерпретироваться существующим компилятором C# либо как

for each (var item in myDictionary)
{ var temp = item; temp .Value += 1; }

or

...assuming MyList is a List<Drawing.Rectangle>
{ temp = MyList[3]; temp.Width += 9; }

оба приводят к ужасному поведению, которое почти наверняка не соответствует намерениям программиста. Разработчики .net решили, что значение того, что члены KeyValuePair<TKey,TValue> могут изменяться по отдельности, не оправдывает опасности, исходящей от первого, но полезность изменения отдельных членов Rectangle была достаточной, чтобы оправдать опасность, создаваемую вторым. Обратите внимание, что ни один из примеров не должен был бы представлять какой-либо опасности, если бы типы использовали открытые поля, а не свойства, поскольку запись в поле временной структуры никогда не была разрешена, даже при вызове установщиков свойств.

person supercat    schedule 12.12.2012

Как упоминалось ранее, KeyValuePair неизменяем. Я подумал, что стоит добавить сюда изменяемую реализацию:

public class MutableKeyValuePair<KeyType, ValueType>
    {
        public KeyType Key { get; set; }
        public ValueType Value { get; set; }

        public MutableKeyValuePair() { }

        public MutableKeyValuePair(KeyType key, ValueType val)
        {
            Key = key;
            Value = val;
        }
    }
person Simon    schedule 15.09.2017

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

mDictionary[trapType] = new KeyValuePair<bool,int>(mDictionary[trapType].Key,mDictionary[trapType].Value +1);

Однако, если вы используете .NET 4, я бы посоветовал вам использовать Tuple вместо пары ключ-значение, если вы пытаетесь просто иметь объект, который содержит два других значения. То есть, если между ними нет отношения ключ-значение. Тогда код будет таким:

mDictionary[trapType] = Tuple.Create(mDictionary[trapType].Item1,mDictionary[trapType].Item2 +1);
person Rune FS    schedule 14.05.2012