【问题标题】:The property KeyValuePair<TKey, Tvalue>.Value has no setter属性 KeyValuePair<TKey, Tvalue>.Value 没有设置器
【发布时间】:2012-05-14 08:44:41
【问题描述】:

我正在使用Dictionary&lt;int, KeyValuePair&lt;bool, int&gt;&gt; 来保存数据。

有时我需要增加KeyValuePair 中的int,但它不会让我这样做,因为它没有设置器。有没有办法增加它?

代码示例:

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

【问题讨论】:

    标签: c# .net keyvaluepair


    【解决方案1】:

    有没有办法增加它?

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

    你必须这样写:

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

    这很丑 - 你真的需要KeyValuePair的值吗?

    【讨论】:

    • 我建议Tuple。创建一个的最短方法是Tuple.Create(existingValue.Key, existingValue.Value + 1)。虽然创建一个类,如果合乎逻辑的话,最好避免不必要的new()
    • @YoryeNathan:是的,这可能是合适的 - 或者是具有反映 boolint 真正含义的属性名称的单独类型。 (我看到你也为此编辑了你的评论:)
    • 是的,虽然我可以想象这将在小范围内用于某些古怪算法的情况,在这种情况下,我个人更喜欢匿名类型。
    【解决方案2】:
    mDictionary[trapType] = new KeyValuePair<bool, int>(mDictionary[trapType].Key, mDictionary[trapType].Value+1)
    

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

        另一种解决方案是创建一个新字典并将新的值和键传递给它:

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

        【讨论】:

          【解决方案5】:

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

          不幸的是,微软似乎一直不愿意让框架类型公开任何公共字段,即使对于像 KeyValuePair&lt;TKey,TValue&gt;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 的实现者认为,让KeyValuePair&lt;TKey,TValue&gt; 的成员单独可变的价值并不能证明前者带来的危险,但修改Rectangle 的各个成员的有用性足以证明第二个带来的危险是正当的。 .请注意,如果类型使用暴露的字段而不是属性,则这两个示例都不会造成任何危险,因为从未允许写入临时结构的字段,即使调用属性设置器也是如此。

          【讨论】:

            【解决方案6】:

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

            【讨论】:

              【解决方案7】:

              您将需要构造一个新的键值对。

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

              【讨论】:

                猜你喜欢
                • 2011-01-16
                • 1970-01-01
                • 2014-02-19
                • 1970-01-01
                • 2013-08-12
                • 1970-01-01
                • 2017-01-17
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多