Подтвердить что ты не робот

Как статическое поле readonly может быть нулевым?

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

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

    private AccountManager()
    {
    }

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

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

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

4b9b3361

Ответ 1

Цитата MSDN ThreadStaticAttribute:

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

Ответ 2

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

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

[ThreadStatic]
readonly static private AccountManager _instance;

private AccountManager()
{
}

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

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

Ответ 3

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

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

Ответ 4

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

Ответ 5

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