Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot modify the return value of Dictionary because it is not a variable

Tags:

c#

Have such error: Cannot modify the return value of 'System.Collections.Generic.Dictionary.this[string]' because it is not a variable.`

My code:

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

            }
        }
    }
    ....
}

How to iterate urlsLimited[pair.Key].min++?

like image 674
user3407977 Avatar asked Mar 11 '14 21:03

user3407977


3 Answers

You will need to assign the value to a local variable, perform the increment, then set it back to the dictionary.

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

For a good explanation, refer to Jon Skeet's answer on a related question: https://stackoverflow.com/a/6255368/1149773.

like image 112
Douglas Avatar answered Nov 10 '22 00:11

Douglas


Consider something like this:

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

Immutable struct and obvious what you're doing. :)

like image 38
jdphenix Avatar answered Nov 09 '22 23:11

jdphenix


The indexer of the Dictionary returns a copy of lim (because it is a value type). Unless you assign this copy to a variable then any modifications you make to min will be lost. This is why you are getting the error. In your case though you do not want to increment the min field of a copy.

The solutions correctly identify that you can set a new instance of lim to the dictionary via the indexer.

The thing to remember is that you are already iterating over the dictionary at this point, so it seems very inefficient to be then searching the dictionary again for the very item you are currently evaluating. You have to do this because when you iterate the Dictionary this also returns a copy of the data it holds via a KeyValuePair, since that is also a value type. The Value of type lim is also copied into the KeyValuePair since it is a value type too.

I would say that you are better off changing lim from a struct to a class, because then the Value property of the KeyValuePair will then always reference the same instance (not a copy), the code you have written will compile, and become a lot easier to read too.

However if you really need that performance gain of the struct on the reads then I would rework your code so that at the time of adding the values to your dictionary you increment the min field.

like image 38
Matt Avatar answered Nov 10 '22 00:11

Matt