Являются ли закрытые переменные-члены потокобезопасными в коде asp.net за классом? - PullRequest
4 голосов
/ 09 ноября 2011

Я вижу случайное исключение "Коллекция была изменена; перечисление может не выполняться" - InvalidOperationException.

Исключение указывает на строку foreach в фрагменте кода ниже, я знаю, что это происходит при изменении коллекции при перечислении.

Однако в моем сценарии я не вижу реальной возможности того, что это произойдет - если только частный член не является поточно-ориентированным. Я могу ошибаться, но здесь мне нужна помощь, чтобы понять и выяснить .

Вот как выглядит мой код

У меня есть код за классом, который имеет частную коллекцию, такую ​​как

private Dictionary<string, string> _someDictionary = SomeConstantClass.ConstantValue;

В событии prerender страницы завершено, я перечисляю словарь

protected override void OnPagePreRenderComplete(object sender, EventArgs e){
     _someDictionary["AnotherKey"] = "Another value";

     foreach(var dataValuePair in _SomeDictionary){
         //Do some operation
     }
}

У меня также есть открытое свойство, которое может изменять эту коллекцию, но оно установлено в файле ascx, как

<tc: UserControlA runat="server" id="abc" CustomProperty="true" />

и вот его реализация,

public bool CustomProperty{
    set{
         if (value)
            _someDictionary["CustomProperty"] = "Custom Value";
    }
}

Это определенно изменило мою коллекцию переменных-членов - но, насколько я понимаю, это свойство должно быть запущено и выполнено в самом Control Init.

Итак, я до сих пор не вижу сценария, в котором коллекция модифицируется во время события pre render complete.

Есть идеи, что может вызвать исключение ??

другие примечания: на странице определенно много панелей обновления, хотя этот конкретный пользовательский контроль не делает ничего особенного и даже не имеет сценария обратной передачи. Из журнала я вижу, что проблема происходит в HTTP-запросе GET к странице.

Более того: Предложите мне способ (если есть) воспроизвести это.

Для моих друзей, которым было интересно узнать SomeConstantClass.ConstantValue, вот оно

class SomeConstantClass{
  public static Dictionary<string, string> ConstantValue = new Dictionary<string, string> {
                      {"ABCD", "EFGH"},
                      {"HIJK", "LMNO"}
                   };
  }

Ответы [ 2 ]

7 голосов
/ 09 ноября 2011

Если вы возвращаете один и тот же экземпляр из SomeConstantClass.ConstantValue, то на нескольких страницах будет переменная приватного члена, указывающая на один и тот же объект. Это приведет к тому, что объект будет изменен в начале одной страницы, а его итерация - на OnPagePreRenderComplete другой страницы.

Убедитесь, что вы возвращаете новый экземпляр словаря при каждом доступе к SomeConstantClass.ConstantValue. Пример:

public static Dictionary<string, string> ConstantValue
{
    get
    {
        return new Dictionary<string, string>
        {
            {"ABCD", "EFGH"},
            {"HIJK", "LMNO"}
        };
    }
}

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

В основном закрытые переменные-члены являются поточно-ориентированными, только если они ссылаются на объект, который является частным для этой страницы, и никто больше не знает об этом объекте или сам объект предназначен для поточно-ориентированного. Инкапсуляция доступа к не поточно-безопасному статическому объекту через закрытый член не сделает его поточно-безопасным.

2 голосов
/ 09 ноября 2011

Если вы знаете, что не делитесь словарем между запросами (или делаете это преднамеренно), вы можете пропустить попытку выяснить, почему, и просто использовать Concurrent Dictionary , который является поточно-ориентированным,Тот факт, что словарь является частным, не делает его безопасным для потоков.

...