-1

编辑:大多数时候它工作正常,错误是异常的。

在调用此方法的行上,错误报告说它抛出了一个 KeyNotFoundException“我将枚举映射到字符串(!我在声明时没有以任何方式更新字典!):

public Task<bool> UpdateStatusAsync(Some object, Status status)
{
    var somerequest = new Somerequest 
    {
        ...
        Status = MapDomainStatusToAclStatus(status.Type),
        ...
    };

    .............
}

这是映射函数:

private string MapDomainStatusToAclStatus(DomainStatus domainStatus)
{
    if (DictionaryDomainACLStatus.ContainsKey(domainStatus))
    {
        return DictionaryDomainACLStatus[domainStatus];
    }

    // Some refactor todo comment.
    switch (domainStatus)
    {
        case DomainStatus.Aborted:
            return "Some string";
    }

    Log.Info($"[MapDomainStatusToAclStatus] DomainStatus={domainStatus} cant be mapped to ACL status");
    return String.Empty;
}

这甚至可能吗?

编辑:

因为我收到了一些关于可能的竞争条件的回复,所以我想补充一点,字典是这样声明的:

 public static readonly Dictionary<DomainStatus, string> { values }

Edit2:我的字典声明:

public static readonly Dictionary<DomainStatus, string> DictionaryDomainACLStatus= new Dictionary<DomainStatus, string>
    {
            {DomainStatus.Approved, "TEXT" },
            {DomainStatus.Declined, "TEXT2" }
    };

稍后在代码中不会发生创建更新删除操作。

4

3 回答 3

1

您的问题是您在并发代码中,这意味着多个代码线程可能同时运行。所以你必须确保并发操作是原子的,即操作总是在多线程环境中作为一个步骤执行,另一个线程不能中断它。

编码...

if (DictionaryDomainACLStatus.ContainsKey(domainStatus))
{
    return DictionaryDomainACLStatus[domainStatus];
}

...显然不是原子的,因为它由两个独立的步骤组成。在ContainsKey和索引器之间,另一个线程可以修改字典,这会导致您KeyNotFoundException的修改是否为Remove.

想到的第一个想法是将这两个步骤替换为...

if (DictionaryDomainACLStatus.TryGetValue(domainStatus, out string value)) {
    return value;
}

但这对您没有帮助,因为TryGetValue它本身不是原子的,这意味着它可以在内部被另一个线程中断。

这个问题的一个常见解决方案是引入一个带有的关键部分lock

lock (myCriticalSection) {
    if (DictionaryDomainACLStatus.ContainsKey(domainStatus))
    {
        return DictionaryDomainACLStatus[domainStatus];
    }
}

字典的任何访问都必须在lock同一个临界区中执行。

另一种选择是使用 a ConcurrentDictionary,它提供原子操作。这只有在对字典的所有 访问都可以在一个(原子)步骤中执行时才有效。这就是为什么通常使用锁会更好。

于 2018-10-24T08:00:08.847 回答
1

您的静态字典在所有线程之间共享,因此不是线程安全的。查看它是否真的需要是静态的,或者查看线程安全的ConcurrentDictionary 。

于 2018-10-24T07:18:20.363 回答
0

我发现错误在于另一段代码,我忽略了它。谢谢大家和我一起思考。在调试时我肯定会更精确。

于 2019-02-06T08:59:00.447 回答