2010-01-11 13 views
27

Also hier ist ein Auszug aus einer meiner Klassen:Wie kann ein schreibgeschütztes Feld null sein?

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

    private AccountManager() 
    { 
    } 

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

Wie Sie sehen können, ist es ein Singleton-per-Thread - das heißt, die Instanz mit dem Threadstatic Attribute gekennzeichnet. Die Instanz wird auch als Teil der statischen Konstruktion instanziiert.

Also, wie ist es möglich, dass ich eine NullReferenceException in meiner ASP.NET MVC-Anwendung bekomme, wenn ich versuche, die Instance-Eigenschaft zu verwenden?

+1

zeigen, wo Sie versuchen, es zu benutzen, die von einem Wrapper in der ASP.NET-Anwendung verbraucht wird, kann helfen, wo die nullref Beflaggung ist – curtisk

+0

Es wird - public IAccount Get (String E-Mail) { return Account .Beispiel.Holen (E-Mail); } Das könnte kniffliger sein als ich dachte; das Töten des Webservers (der eingebauten in VS) und das Neustarten der Anwendung haben das Problem verschwinden lassen ... – gerrod

Antwort

38

MSDN ThreadStaticAttribute Zitiert:

Geben Sie keine Anfangswerte für Felder mit Thread, weil solche Initialisierung nur einmal auftritt, wenn der Klasse Konstruktor ausführt und wirkt sich daher nur ein Thread. Wenn Sie keinen Anfangswert angeben, können Sie auf das Feld verlassen auf den Standardwert initialisiert ist, wenn es ein Werttyp ist, oder auf einen Null Verweis (Nothing in Visual Basic), wenn ist es eine Referenz Art.

+0

+1 für die Bereitstellung der Referenz –

+0

Einverstanden, ich habe dies als die Antwort markiert. Danke Austin! – gerrod

1

Ich glaube nur das, was passiert ist, dass das statische Feld einmal initialisiert ist so, wenn ein anderer Thread das Feld zu lesen versucht es null sein wird (da seinen Standardwert), da _instance nicht erneut initialisiert werden kann. Es ist nur ein Gedanke, aber ich könnte völlig daneben sein, aber das ist es, was ich denke.

12

Dies ist ein verwirrender Teil des Attributs ThreadStatic. Obwohl er einen Wert pro Thread erstellt, wird der Initialisierungscode nur für einen der Threads ausgeführt. Alle anderen Threads, die auf diesen Wert zugreifen, erhalten den Standardwert für diesen Typ anstelle des Ergebnisses des Initialisierungscodes.

Anstatt der Wert Initialisierung, wickeln Sie es in eine Eigenschaft, die die Initialisierung für Sie vornimmt.

[ThreadStatic] 
readonly static private AccountManager _instance; 

private AccountManager() 
{ 
} 

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

Da der Wert _instance pro Thread eindeutig ist, ist keine Verriegelung in der Eigenschaft erforderlich, und es kann wie jeder anderen lazily initialisierten Wert behandelt werden.

+0

Danke Jared; Meine Lösung sieht Ihrer ähnlich, aber das wusste ich nicht über ThreadStatic. Also täusche mich! – gerrod

8

Sie haben hier einen klassischen [ThreadStatic] "101" getroffen. nur einmal

Die statischen Initialisierer werden Feuer, obwohl es als [ThreadStatic] markiert, so dass andere Threads (abgesehen von den ersten) werden diese uninitialised sehen.

0

Ein statisches Feld, das mit ThreadStaticAttribute markiert ist, wird nicht zwischen Threads geteilt. Jeder ausführende Thread verfügt über eine separate Instanz des Felds und legt unabhängig voneinander Werte für dieses Feld fest. Wenn auf das Feld in einem anderen Thread zugegriffen wird, enthält es einen anderen Wert.