KeyValuePair<TKey, Tvalue>.Value属性没有setter。

8
我正在使用一个Dictionary<int, KeyValuePair<bool, int>>来保存数据。
有时我需要增加KeyValuePair中的int,但是它没有setter,所以我无法这样做。是否有一种方法可以增加它?
代码示例:
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
7个回答

22

有没有一种方法可以对它进行递增?

没有。 KeyValuePair 是不可变的 - 它也是一个值类型,因此在创建副本后更改Value属性的值也无济于事。

您必须编写类似以下内容的代码:

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

尽管如此,这样还是很丑陋 - 你真的需要值是一个KeyValuePair吗?


3
我建议使用“元组(Tuple)”,用最短的方式创建一个是使用Tuple.Create(existingValue.Key, existingValue.Value + 1)。如果逻辑上合理,创建一个类会更好,以避免不必要的new() - SimpleVar
@YoryeNathan:是的,这可能是合适的 - 或者使用属性名称反映boolint的实际含义的单独类型。 (我也看到您已经为此编辑了您的评论 :)) - Jon Skeet
是的,虽然我可以想象在某些古怪的算法的小范围内可能会使用它,但在这种情况下,我个人更喜欢匿名类型。 - SimpleVar

0
另一个解决方案是创建一个新的字典,并将新值和键传递给它:
foreach (var d in existingDic)
                    newDic.Add(d.Key, d.Value + 1);

0

如先前所述,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;
        }
    }

0

KeyValuePair 通常只用作字典的迭代器值。如果你想要它是可变的,最好定义自己的类型。


0

从概念上讲,KeyValuePair<TKey,TValue>只是一对变量,KeyValue。如果Microsoft使用公开字段KeyValue来实现它,那么它的语义将是完美的;当用作ForEach控制变量时,它将是不可变的,但可以更新普通变量或数组元素的Key或Value字段而无需更新另一个。

不幸的是,Microsoft似乎不愿意让框架类型暴露任何公共字段,即使是像KeyValuePair<TKey,TValue>Drawing.Rectangle这样的类型,其语义规定:(1)该类型必须是一个结构体;(2)它的整个状态在一组固定属性中可见(除了定义对象状态的属性之外,可能还有其他计算属性),(3)这些属性可以分配适合它们类型的任何组合值。因此,Microsoft只考虑了将类型状态组成成员公开为只读属性或读写属性的可能性。使用读写属性意味着像下面这样的代码:

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

或者

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

现有的C#编译器将解释为以下任一方式:

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

或者

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

两者都会产生可怕的行为,几乎肯定不是程序员想要的。.net的实现者们认为,让的成员单独可变的价值不足以证明前者所带来的危险,但修改的单个成员的有用性足以证明第二个所带来的危险。请注意,如果使用的类型公开了字段而不是属性,则这两个示例都不必造成任何危险,因为即使在调用属性设置器时,写入临时结构的字段也从未被允许。


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

0

你需要构建一个新的键值对。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接