Question

I'm using a Dictionary<int, KeyValuePair<bool, int>> to hold data.

From time to time I need to increment the int in the KeyValuePair, but it won't let me, because it has no setter. Is there a way to increment it?

Code sample:

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
Was it helpful?

Solution

Is there a way to increment it?

No. KeyValuePair is immutable - it's also a value type, so changing the value of the Value property after creating a copy wouldn't help anyway.

You'd have to write something like this:

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

It's pretty ugly though - do you really need the value to be a KeyValuePair?

OTHER TIPS

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

KeyValuePair tends just to be used as an iterator value for dictionaries. You're better off defining your own type if you want it to be mutable.

another solution is to create a new dictionary and pass the new values and keys to it:

foreach (var d in existingDic)
                    newDic.Add(d.Key, d.Value + 1);

Conceptually, KeyValuePair<TKey,TValue> is just a pair of variables, Key and Value. Had Microsoft implemented it with exposed public fields Key and Value, the semantics of it would have been perfect; when used as a ForEach control variable it would have been immutable, but one could have updated the Key or Value field of an ordinary variable or array element without having to update the other.

Unfortunately, Microsoft seems to have been unwilling to have framework types expose any public fields, even for types like KeyValuePair<TKey,TValue> or Drawing.Rectangle whose semantics dictate that (1) the type must be a struct; (2) its entire state is visible in a fixed set of properties (there may be other computed properties beyond those which define an object's state), and (3) those properties may be assigned any combination of values suitable for their types. Consequently, Microsoft only considered the possibilities of exposing the members comprising the types' state as read-only properties, or as read-write properties. Using read-write properties would mean that code like:

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

or

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

would be interpreted by the existing C# compiler as either

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

both of yield horrible behavior which is almost certainly not what the programmer intended. The implementers of .net decided that the value of having the members of KeyValuePair<TKey,TValue> be individually mutable did not justify the danger posed by the former, but the usefulness of modifying individual members of Rectangle was sufficient to justify the danger posed by second. Note that neither example would have had to pose any danger had the types used exposed fields rather than properties, since writing to a field of a temporary struct has never been permissible, even when calling property setters was.

As previously mentioned, the KeyValuePair is immutable. I thought it was worth adding here a mutable implementation:

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

You will need to construct a new key value pair.

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

However if you are on .NET 4, I'd suggest you use a Tuple instead of a key value pair if what you are trying to do is simply to have an object that holds two other values. Ie if there's no key-value relationship between the two. Then code would then be:

mDictionary[trapType] = Tuple.Create(mDictionary[trapType].Item1,mDictionary[trapType].Item2 +1);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top