Как статическое поле только для чтения может быть нулевым? - PullRequest
27 голосов
/ 11 января 2010

Итак, вот выдержка из одного из моих занятий:

    [ThreadStatic]
    readonly static private AccountManager _instance = new AccountManager();

    private AccountManager()
    {
    }

    static public AccountManager Instance
    {
        get { return _instance; }
    }

Как видите, это одиночный поток, т. Е. Экземпляр помечен атрибутом ThreadStatic. Экземпляр также создается как часть статической конструкции.

В таком случае, как это возможно, что я получаю исключение NullReferenceException в моем приложении ASP.NET MVC, когда я пытаюсь использовать свойство Instance?

Ответы [ 5 ]

38 голосов
/ 11 января 2010

Цитирование MSDN ThreadStaticAttribute :

Не указывайте начальные значения для поля помечены ThreadStaticAttribute, потому что такой инициализация происходит только один раз, когда конструктор класса выполняется, и поэтому влияет только на одну нить. Если Вы не указываете начальное значение, Вы можете положиться на поле инициализируется значением по умолчанию, если оно тип значения или ноль ссылка (ничего в Visual Basic), если это ссылочный тип.

12 голосов
/ 11 января 2010

Это запутанная часть атрибута ThreadStatic. Несмотря на то, что он создает значение для каждого потока, код инициализации запускается только в одном из потоков. Все остальные потоки, которые получают доступ к этому значению, получат значение по умолчанию для этого типа вместо результата кода инициализации.

Вместо инициализации значения оберните его в свойство, которое выполняет инициализацию за вас.

[ThreadStatic]
readonly static private AccountManager _instance;

private AccountManager()
{
}

static public AccountManager Instance
{
  get 
  { 
    if ( _instance == null ) _instance = new AccountManager();
    return _instance; 
  }
}

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

8 голосов
/ 11 января 2010

Вы попали в классическую [ThreadStatic] "101" здесь.

Статический инициализатор срабатывает только один раз, , хотя помечен как [ThreadStatic], поэтому другие потоки (кроме первого) увидят это неинициализированным.

1 голос
/ 11 января 2010

Я считаю, что происходит то, что статическое поле инициализируется только один раз, поэтому, когда другой поток пытается прочитать поле, оно будет нулевым (так как его значение по умолчанию), поскольку _instance не может быть инициализирован снова. Это всего лишь мысль, но я мог бы быть совсем далеко, но я думаю, что это происходит.

0 голосов
/ 12 ноября 2013

Статическое поле, помеченное ThreadStaticAttribute, не распределяется между потоками. Каждый исполняющий поток имеет отдельный экземпляр поля и независимо устанавливает и получает значения для этого поля. Если доступ к полю осуществляется в другом потоке, он будет содержать другое значение.

...