Sdílet prostřednictvím


Statické konstruktory (Průvodce programováním v C#)

Statický konstruktor se používá k inicializaci jakýchkoli statických dat nebo k provedení konkrétní akce, kterou je potřeba provést pouze jednou. Volá se automaticky před vytvořením první instance nebo odkazem na všechny statické členy. Statický konstruktor se volá maximálně jednou.

class SimpleClass
{
    // Static variable that must be initialized at run time.
    static readonly long baseline;

    // Static constructor is called at most one time, before any
    // instance constructor is invoked or member is accessed.
    static SimpleClass()
    {
        baseline = DateTime.Now.Ticks;
    }
}

Existuje několik akcí, které jsou součástí statické inicializace. Tyto akce se provádějí v následujícím pořadí:

  1. Statická pole jsou nastavená na hodnotu 0. Modul runtime obvykle tuto inicializaci provede.
  2. Spustí se inicializátory statických polí. Inicializátory statických polí ve většině odvozených typů se spouští.
  3. Spustí se inicializátory statických polí základního typu. Inicializátory statických polí začínající přímou základnou prostřednictvím každého základního typu do System.Object.
  4. Spustí se libovolný statický konstruktor. Všechny statické konstruktory, od konečné základní třídy prostřednictvím každé základní třídy Object.Object prostřednictvím spuštění typu. Pořadí provádění statického konstruktoru není zadané. Všechny statické konstruktory v hierarchii se však spouští před vytvořením všech instancí.

Důležité

Existuje jedna důležitá výjimka pravidla, které statický konstruktor spouští před vytvořením jakékoli instance. Pokud inicializátor statického pole vytvoří instanci typu, spustí se tento inicializátor (včetně jakéhokoli volání konstruktoru instance) před spuštěním statického konstruktoru. Toto je nejběžnější v jednom vzoru , jak je znázorněno v následujícím příkladu:

public class Singleton
{
    // Static field initializer calls instance constructor.
    private static Singleton instance = new Singleton();

    private Singleton()
    { 
        Console.WriteLine("Executes before static constructor.");
    }

    static Singleton()
    { 
        Console.WriteLine("Executes after instance constructor.");
    }

    public static Singleton Instance => instance;
}

Inicializátor modulu může být alternativou ke statickému konstruktoru. Další informace najdete ve specifikaci inicializátorů modulů.

Poznámky

Statické konstruktory mají následující vlastnosti:

  • Statický konstruktor nepřebírají modifikátory přístupu ani nemají parametry.
  • Třída nebo struktura může mít pouze jeden statický konstruktor.
  • Statické konstruktory nelze dědit ani přetížit.
  • Statický konstruktor nelze volat přímo a má být volána pouze modulem CLR (Common Language Runtime). Vyvolá se automaticky.
  • Uživatel nemá žádnou kontrolu nad tím, kdy je v programu spuštěn statický konstruktor.
  • Statický konstruktor se volá automaticky. Inicializuje třídu před vytvořením první instance nebo jakékoli statické členy deklarované v této třídě (nikoli její základní třídy) jsou odkazovány. Statický konstruktor se spustí před konstruktorem instance. Pokud jsou inicializátory proměnných statických polí přítomny ve třídě statického konstruktoru, spouští se v textovém pořadí, ve kterém se zobrazují v deklaraci třídy. Inicializátory se spouští bezprostředně před statickým konstruktorem.
  • Pokud nezadáte statický konstruktor pro inicializaci statických polí, budou všechna statická pole inicializována na výchozí hodnotu uvedenou v části Výchozí hodnoty typů jazyka C#.
  • Pokud statický konstruktor vyvolá výjimku, modul runtime ho nevolá podruhé a typ zůstane neinicializovaný po celou dobu životnosti domény aplikace. Nejčastěji je vyvolána výjimka, TypeInitializationException když statický konstruktor nemůže vytvořit instanci typu nebo neošetřené výjimky, ke které dochází v rámci statického konstruktoru. U statických konstruktorů, které nejsou explicitně definované ve zdrojovém kódu, může řešení potíží vyžadovat kontrolu kódu zprostředkujícího jazyka (IL).
  • Přítomnost statického konstruktoru zabraňuje přidání atributu BeforeFieldInit typu. Tím se omezí optimalizace modulu runtime.
  • Pole deklarované jako static readonly může být přiřazeno pouze jako součást deklarace nebo ve statickém konstruktoru. Pokud explicitní statický konstruktor není povinný, inicializovat statická pole při deklaraci, nikoli prostřednictvím statického konstruktoru pro lepší optimalizaci modulu runtime.
  • Modul runtime volá statický konstruktor více než jednou v jedné doméně aplikace. Toto volání se provádí v uzamčené oblasti na základě konkrétního typu třídy. V těle statického konstruktoru nejsou potřeba žádné další mechanismy uzamčení. Abyste se vyhnuli riziku zablokování, nezablokujte aktuální vlákno ve statických konstruktorech a inicializátorech. Například nečekejte na úlohy, vlákna, obslužné rutiny čekání nebo události, nezískávejte zámky a nespouštět blokující paralelní operace, jako jsou paralelní smyčky nebo Parallel.Invoke paralelní dotazy LINQ.

Poznámka:

I když není přímo přístupný, měl by být zdokumentován přítomnost explicitního statického konstruktoru, aby vám pomohl s řešením potíží s výjimkami inicializace.

Využití

  • Typické použití statických konstruktorů je, když třída používá soubor protokolu a konstruktor se používá k zápisu položek do tohoto souboru.
  • Statické konstruktory jsou také užitečné při vytváření tříd obálky pro nespravovaný kód, když konstruktor může volat metodu LoadLibrary .
  • Statické konstruktory jsou také vhodným místem k vynucení kontrol za běhu u parametru typu, které nelze zkontrolovat v době kompilace prostřednictvím omezení parametru typu.

Příklad

V tomto příkladu má třída Bus statický konstruktor. Při vytvoření první instance Bus (bus1), je vyvolán statický konstruktor pro inicializaci třídy. Ukázkový výstup ověří, že statický konstruktor běží pouze jednou, i když jsou vytvořeny dvě instance Bus a že běží před spuštěním konstruktoru instance.

public class Bus
{
    // Static variable used by all Bus instances.
    // Represents the time the first bus of the day starts its route.
    protected static readonly DateTime globalStartTime;

    // Property for the number of each bus.
    protected int RouteNumber { get; set; }

    // Static constructor to initialize the static variable.
    // It is invoked before the first instance constructor is run.
    static Bus()
    {
        globalStartTime = DateTime.Now;

        // The following statement produces the first line of output,
        // and the line occurs only once.
        Console.WriteLine("Static constructor sets global start time to {0}",
            globalStartTime.ToLongTimeString());
    }

    // Instance constructor.
    public Bus(int routeNum)
    {
        RouteNumber = routeNum;
        Console.WriteLine("Bus #{0} is created.", RouteNumber);
    }

    // Instance method.
    public void Drive()
    {
        TimeSpan elapsedTime = DateTime.Now - globalStartTime;

        // For demonstration purposes we treat milliseconds as minutes to simulate
        // actual bus times. Do not do this in your actual bus schedule program!
        Console.WriteLine("{0} is starting its route {1:N2} minutes after global start time {2}.",
                                this.RouteNumber,
                                elapsedTime.Milliseconds,
                                globalStartTime.ToShortTimeString());
    }
}

class TestBus
{
    static void Main()
    {
        // The creation of this instance activates the static constructor.
        Bus bus1 = new Bus(71);

        // Create a second bus.
        Bus bus2 = new Bus(72);

        // Send bus1 on its way.
        bus1.Drive();

        // Wait for bus2 to warm up.
        System.Threading.Thread.Sleep(25);

        // Send bus2 on its way.
        bus2.Drive();

        // Keep the console window open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
/* Sample output:
    Static constructor sets global start time to 3:57:08 PM.
    Bus #71 is created.
    Bus #72 is created.
    71 is starting its route 6.00 minutes after global start time 3:57 PM.
    72 is starting its route 31.00 minutes after global start time 3:57 PM.
*/

specifikace jazyka C#

Další informace naleznete v části Statické konstruktory specifikace jazyka C#.

Viz také