Freigeben über


Statische Felder von Verweistypen inline initialisieren

     TypeName

InitializeReferenceTypeStaticFieldsInline

CheckId

CA1810

Kategorie

Microsoft.Performance

Unterbrechende Änderung

NonBreaking

Ursache

Ein Verweistyp deklariert einen expliziten statischen Konstruktor.

Regelbeschreibung

Wenn ein Typ einen expliziten statischen Konstruktor deklariert, überprüft der JIT-(Just in Time-)Compiler jede der statischen Methoden und Instanzenkonstruktoren des Typs. Dadurch wird sichergestellt, dass zuvor der statische Konstruktor aufgerufen wurde. Die statische Initialisierung wird ausgelöst, wenn auf einen statischen Member zugegriffen wird oder wenn eine Instanz des Typs erstellt wird. Die statische Initialisierung wird allerdings nicht ausgelöst, wenn eine Variable des Typs zwar deklariert, aber nicht verwendet wird. Die Nichtverwendung kann von großer Bedeutung sein, wenn durch die Initialisierung der globale Zustand verändert wird.

Wenn alle statischen Daten inline initialisiert werden und kein expliziter statischer Konstruktor deklariert wird, fügen MSIL-(Microsoft Intermediate Language-)Compiler die beforefieldinit-Flag und einen impliziten statischen Konstruktor hinzu, welcher die statischen Daten gemäß der MSIL-Typdefinition initialisiert. Wenn der JIT-Compiler auf die beforefieldinit-Flag trifft, werden meist keine zusätzlichen Konstruktorüberprüfungen durchgeführt. Die statische Initialisierung wird auf jeden Fall vor dem Zugriff auf die statischen Felder durchgeführt, aber erst nachdem eine statische Methode/ein Instanzenkonstruktor aufgerufen wurde. Die statische Initialisierung kann zu jedem Zeitpunkt nach der Deklarierung einer Typvariablen durchgeführt werden.

Durch die Überprüfung statischer Konstruktoren kann die Leistung herabgesetzt werden. Häufig werden statische Konstruktoren ausschließlich zur Initialisierung statischer Felder verwendet. In diesen Fällen ist lediglich zu beachten, dass die statische Initialisierung vor dem ersten Zugriff auf das statische Feld erfolgen muss. Das beforefieldinit-Verhalten ist für diese und die meisten anderen Typen geeignet. Es ist nur dann ungeeignet, wenn durch die statische Initialisierung der globale Zustand beeinflusst wird, und eine der folgenden Aussagen zutrifft:

  • Die Auswirkung auf den globalen Zustand ist mit hohen Kosten verbunden und wird nicht benötigt, wenn der Typ nicht verwendet wird.

  • Der Zugriff auf die Auswirkungen auf den globalen Zustand kann ohne gleichzeitigen Zugriff auf irgendeines der statischen Felder des Typs erfolgen.

Behandlung von Verstößen

Um einen Verstoß gegen diese Regel zu beheben, initialisieren Sie alle statischen Daten nach deren Deklaration und entfernen den statischen Konstruktor.

Warnungsausschluss

Eine Warnung dieser Regel kann in folgenden Fällen gefahrlos ausgeschlossen werden: Die Leistung ist kein Kriterium; die Änderungen des globalen Zustands aufgrund der statischen Initialisierung verursachen hohe Kosten; die Änderungen des globalen Zustands müssen auf jeden Fall erfolgen, bevor eine statische Methode des Typs aufgerufen wird oder eine Instanz des Typs erstellt wird.

Beispiel

Im folgenden Beispiel wird ein Typ gezeigt, der gegen die Regel verstößt (StaticConstructor), und ein Typ, der den statischen Konstruktor zwecks Regelkonformität durch eine Inlineinitialisierung ersetzt (NoStaticConstructor).

Imports System
Imports System.Resources

Namespace PerformanceLibrary

   Public Class StaticConstructor

      Shared someInteger As Integer
      Shared resourceString As String 

      Shared Sub New()

         someInteger = 3
         Dim stringManager As New ResourceManager("strings", _
            System.Reflection.Assembly.GetExecutingAssembly())
         resourceString = stringManager.GetString("string")

      End Sub

   End Class


   Public Class NoStaticConstructor

      Shared someInteger As Integer = 3
      Shared resourceString As String = InitializeResourceString()

      Shared Private Function InitializeResourceString()

         Dim stringManager As New ResourceManager("strings", _
            System.Reflection.Assembly.GetExecutingAssembly())
         Return stringManager.GetString("string")

      End Function

   End Class

End Namespace
using System;
using System.Reflection;
using System.Resources;

namespace PerformanceLibrary
{
   public class StaticConstructor
   {
      static int someInteger;
      static string resourceString;

      static StaticConstructor()
      {
         someInteger = 3;
         ResourceManager stringManager = 
            new ResourceManager("strings", Assembly.GetExecutingAssembly());
         resourceString = stringManager.GetString("string");
      }
   }

   public class NoStaticConstructor
   {
      static int someInteger = 3;
      static string resourceString = InitializeResourceString();

      static string InitializeResourceString()
      {
         ResourceManager stringManager = 
            new ResourceManager("strings", Assembly.GetExecutingAssembly());
         return stringManager.GetString("string");
      }
   }
}

Beachten Sie die hinzugefügte beforefieldinit-Flag auf der MSIL-Definition der NoStaticConstructor-Klasse.

Ausgabe

.class public auto ansi StaticConstructor
       extends [mscorlib]System.Object
{
} // end of class StaticConstructor

.class public auto ansi beforefieldinit NoStaticConstructor
       extends [mscorlib]System.Object
{
} // end of class NoStaticConstructor

Verwandte Regeln

Statische Felder für Werttyp inline initialisieren