【问题标题】:Updating the key object in AddOrUpdate method在 AddOrUpdate 方法中更新密钥对象
【发布时间】:2015-01-30 16:15:54
【问题描述】:

我有一个测试类。

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

我想设置一个 ConcurrentDictionary,其中一个 int 作为键,Test 作为值。

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

我想为此字典编写 AddorUpdate 的 Update 部分,以便如果外部变量(例如 External)为 true,则该 Test 实例的 Val 应增加 100,但如果 bool 为 false,则应减少100. 谁能帮我,我该怎么做。我只是不确定如何使用 lambda 访问字典中的 Test 实例。尽管有 lambda,我也可以进行方法调用吗?

【问题讨论】:

    标签: c# .net-4.0 concurrentdictionary


    【解决方案1】:

    类似:

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

    您示例中的bool External 最终会在匿名方法中作为闭包,因此它会变得非常奇怪并产生意想不到的结果。你会想以某种方式解决这个问题。

    编辑:

    我对这种方法不满意。我建议去一个普通的Dictionary&lt;int, Test&gt; 并拉出当前值并更新它,所有这些都用ReaderWriterLockSlim 来确保状态。

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

    最后,请务必将External 标记为volatile 以创建内存屏障并防止可能给您提供过时值的优化。

    【讨论】:

    • 我可以把这个 lambda 放到一个外部函数中吗?此外,我不需要围绕此代码进行任何锁定,对吗?
    • 我想你可以把 lambda 变成一个外部函数。我会推荐我编辑的方法。
    • 那么有没有办法用 ConcurrentDictionary 处理闭包?我知道对于任务,您可以传入参数来制作本地副本。
    • 这里的问题是AddOrUpdate 方法有一个特定的签名,你不能真正扩充它以包含没有闭包的变量。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-24
    • 2019-12-26
    • 1970-01-01
    • 2021-07-07
    • 1970-01-01
    • 2013-03-07
    相关资源
    最近更新 更多