不能修改字典的返回值,因为它不是一个变量。

7

出现这样的错误: 无法修改“System.Collections.Generic.Dictionary.this[string]”的返回值,因为它不是一个变量。

我的代码:

Dictionary<string, lim> urlsLimited = new Dictionary<string, lim>();
struct lim
{
    public int min;
    public int max;
}
void main ()
{
    ....
    foreach (KeyValuePair<string, lim> pair in urlsLimited)
    {
        string like = od.LikeDiscussions(pair.Key);
        if (like == "Like")
        {
            lock (locker)
            {
                urlsLimited[pair.Key].min++; // error

            }
        }
    }
    ....
}

如何迭代 urlsLimited [pair.Key] .min++?

9
可变结构体是有害的。这是你应该避免使用它们的一个(众多)原因之一。 - Servy
3个回答

10
你需要将值分配给一个本地变量,进行增量操作,然后将其设置回字典。
foreach (KeyValuePair<string, lim> pair in urlsLimited)
{
    string like = od.LikeDiscussions(pair.Key);
    if (like == "Like")
    {
        lock (locker)
        {
            lim val = pair.Value;
            val.min++;
            urlsLimited[pair.Key] = val;
        }
    }
}

有关此问题的详细解释,请参考Jon Skeet在相关问题中的回答:https://dev59.com/kW025IYBdhLWcg3wChOc#6255368


3
我通常会使用“不可变结构体”使操作更加明显:var oldLim = pair.Value; urlsLimit[pair.Key] = new lim { min = oldLim + 1, max = oldLim.max }; - user2864740

4
考虑下面这个例子:

假设有这样一个场景:


struct lim {
  public readonly int min;
  public readonly int max;

  public lim(int min = 0, int max = 0) {
    this.min = min;
    this.max = max;
  }
}

// ... later in your loop body
var currentLim = urlsLimited[pair.Key];
urlsLimited[pair.Key] = new lim(currentLim.min + 1, currentLim.max);

不可变的结构体,显而易见你正在做什么。 :)


2
Dictionary 的索引器返回 lim 的一个副本(因为它是值类型)。除非你将此副本分配给一个变量,否则对 min 所做的任何修改都将丢失。这就是你出现错误的原因。在你的情况下,你不想增加副本的 min 字段。
解决方案正确地指出,你可以通过索引器将新实例的 lim 设置到字典中。
需要记住的是,在这个时候,你已经在迭代字典了,所以似乎很低效地再次搜索你正在评估的项目。你必须这样做,因为当你迭代 Dictionary 时,它也通过 KeyValuePair 返回其持有的数据的副本,因为那也是值类型。由于 Value 也是值类型,所以它也被复制到 KeyValuePair 中。
我会说,最好将 lim 从结构体改为类,因为这样 KeyValuePairValue 属性将始终引用相同的实例(而不是副本),你编写的代码将编译,并且读起来也更容易。
但是,如果你真的需要结构体在读取时的性能提升,那么我建议你重新设计代码,在将值添加到字典时增加 min 字段。

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