Как этот кусок кода может генерировать исключение KeyNotFoundException, когда словарь доступен только для чтения и никогда не обновляется !?Большую часть времени это работает нормально - PullRequest
0 голосов
/ 24 октября 2018

Редактировать: в большинстве случаев она работает нормально, ошибка является исключительной.

В строке, где этот метод вызывается, в отчете об ошибке говорится, что он вызвал исключение KeyNotFoundException, «которое отображает перечисление в строку (! Imне обновлять словарь каким-либо образом заполненным при объявлении!):

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

Позже в коде не выполняются операции создания и удаления обновлений.

Ответы [ 3 ]

0 голосов
/ 24 октября 2018

Ваша проблема в том, что вы находитесь в параллельном коде, что означает, что несколько потоков кода могут работать одновременно.Таким образом, вы должны убедиться, что одновременные операции атомарные , т. Е. Что операция всегда выполняется как один шаг в многопоточной среде, и другой поток не может ее прервать.

код ...

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

... явно не атомарный, потому что состоит из двух отдельных шагов.Между ContainsKey и индексатором другой поток может изменить словарь, что приводит к вашему KeyNotFoundException, если модификация является Remove.

Первой мыслью, которая приходит на ум, будет замена этих двух шагов.by ...

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

Это не поможет, хотя TryGetValue само по себе не является атомарным, что означает, что оно может быть прервано другим потоком внутри.

Распространенное решениек этой проблеме относится введение критической секции с lock:

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

Любой доступ к словарю должен быть выполнен в пределах lock той же критическойsection.

Другой вариант - использовать ConcurrentDictionary, который обеспечивает атомарные операции.Это будет работать только в том случае, если все доступы к словарю могут быть выполнены за один (атомарный) шаг.Вот почему обычно вам будет лучше с замком.

0 голосов
/ 06 февраля 2019

Я обнаружил, что ошибка заключается в другом фрагменте кода, и я упустил из виду.Спасибо всем, что подумали вместе со мной.Я определенно буду более точен при отладке.

0 голосов
/ 24 октября 2018

Ваш статический словарь доступен для всех потоков и поэтому не является потокобезопасным.Проверьте, действительно ли он должен быть статическим, или посмотрите на ConcurrentDictionary , который является потокобезопасным.

...