0

I have a Test class.

class Test
{
    public int Id { get; set; }
    public int Val { get; set; }
}

I would like to setup a ConcurrentDictionary with an int as Key and Test as the value.

bool External = true;
ConcurrentDictionary<int, Test> data = new ConcurrentDictionary<int, Test>();

I would like to write the Update part of AddorUpdate for this dictionary so that if an external variable (say External) is true then the Val for that instance of Test should increment by 100 but if bool is false then it should decrement by 100. Can someone help me how can I do it. I am just not sure how can I get access to the Test instance in the dictionary using a lambda. Also can I have an method call in spite of the lambda?

paul deter
  • 857
  • 2
  • 7
  • 20

1 Answers1

2

Something like:

data.AddOrUpdate(key, test, (k, t) =>
{
    var newTest = new Test { Id = t.Id, Val = t.Val };
    if (External)
        newTest.Val += 100;
    else
        newTest.Val -= 100;

    return newTest;
});

The bool in your example, External, will end up as a closure in the anonymous method so it'll get really weird and have unexpected results. You'll want to work around that somehow.

EDIT:

I'm not happy with this approach. I suggest going to a regular Dictionary<int, Test> and pulling the current value out and updating it, all with a ReaderWriterLockSlim to ensure state.

var key = ...;
var lock = new ReaderWriterLockSlim();

lock.EnterWriteLock();
try
{
    if (dict.ContainsKey(key))
    {
        // update without closures
        var test = dict[key];
        if (External)
            test.Val += 100;
        else
            test.Val -= 100;
    }
}
else
{
    // insert
    var test = new Test { ...initial state... };
    dict.Add(key, test);
}
finally
{
    lock.ExitWriteLock();
}

Finally, be sure to mark External as volatile to create a memory barrier and prevent optimization that might give you an outdated value.

Haney
  • 32,775
  • 8
  • 59
  • 68
  • Can I have this lambda into an external function? Also I don't need to have any locks around this code, correct? – paul deter Jan 30 '15 at 16:31
  • 2
    You could make the lambda into an external function I suppose. I'd recommend my edited approach instead. – Haney Jan 30 '15 at 16:35
  • 1
    So there is no way of handling closures with ConcurrentDictionary? I know with tasks you can pass in parameters which makes a local copy. – paul deter Jan 30 '15 at 16:40
  • The problem here is that the `AddOrUpdate` method has a specific signature, and you can't really augment it to contain the variable without a closure. – Haney Jan 30 '15 at 16:45