Statische constructors (C#-programmeerhandleiding)
Een statische constructor wordt gebruikt om statische gegevens te initialiseren of om een bepaalde actie uit te voeren die slechts één keer moet worden uitgevoerd. Deze wordt automatisch aangeroepen voordat het eerste exemplaar wordt gemaakt of waarnaar wordt verwezen door statische leden. Een statische constructor wordt maximaal één keer aangeroepen.
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;
}
}
Er zijn verschillende acties die deel uitmaken van statische initialisatie. Deze acties vinden plaats in de volgende volgorde:
- Statische velden zijn ingesteld op 0. De runtime voert deze initialisatie doorgaans uit.
- Statische veld initialisaties worden uitgevoerd. De statische veld-initialisaties in de meest afgeleide typeuitvoering.
- Initialisatiefunctie voor statisch veld van basistype wordt uitgevoerd. Statische veld initialisaties beginnend met de directe basis door elk basistype naar System.Object.
- Elke statische constructor wordt uitgevoerd. Statische constructors, van de ultieme basisklasse van Object.Object elke basisklasse tot en met de uitvoering van het type. De volgorde van de uitvoering van een statische constructor wordt niet opgegeven. Alle statische constructors in de hiërarchie worden echter uitgevoerd voordat er exemplaren worden gemaakt.
Belangrijk
Er is een belangrijke uitzondering op de regel die door een statische constructor wordt uitgevoerd voordat een exemplaar wordt gemaakt. Als een statische veld-initialisatiefunctie een exemplaar van het type maakt, wordt die initialisatie uitgevoerd (inclusief een aanroep naar een instantieconstructor) voordat de statische constructor wordt uitgevoerd. Dit komt het meest voor in het singleton-patroon , zoals wordt weergegeven in het volgende voorbeeld:
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;
}
Een module-initialisatiefunctie kan een alternatief zijn voor een statische constructor. Zie de specificatie voor module-initialisaties voor meer informatie.
Opmerkingen
Statische constructors hebben de volgende eigenschappen:
- Een statische constructor heeft geen toegangsaanpassingen of parameters.
- Een klasse of struct kan slechts één statische constructor hebben.
- Statische constructors kunnen niet worden overgenomen of overbelast.
- Een statische constructor kan niet rechtstreeks worden aangeroepen en is alleen bedoeld om te worden aangeroepen door de Common Language Runtime (CLR). Deze wordt automatisch aangeroepen.
- De gebruiker heeft geen controle wanneer de statische constructor wordt uitgevoerd in het programma.
- Een statische constructor wordt automatisch aangeroepen. De klasse wordt geïnitialiseerd voordat het eerste exemplaar wordt gemaakt of eventuele statische leden die zijn gedeclareerd in die klasse (niet de basisklassen) worden verwezen. Een statische constructor wordt uitgevoerd vóór een exemplaarconstructor. Als initialisatieprogramma's voor statische veldvariabelen aanwezig zijn in de klasse van de statische constructor, worden ze uitgevoerd in de tekstvolgorde waarin ze worden weergegeven in de klassedeclaratie. De initialisatieprogramma's worden direct vóór de statische constructor uitgevoerd.
- Als u geen statische constructor opgeeft voor het initialiseren van statische velden, worden alle statische velden geïnitialiseerd naar de standaardwaarde zoals vermeld in de standaardwaarden van C#-typen.
- Als een statische constructor een uitzondering genereert, wordt deze door de runtime niet een tweede keer aangeroepen en blijft het type niet geïnitialiseerd voor de levensduur van het toepassingsdomein. Meestal wordt er een TypeInitializationException uitzondering gegenereerd wanneer een statische constructor geen instantie kan maken van een type of voor een niet-verwerkte uitzondering die zich in een statische constructor voordoet. Voor statische constructors die niet expliciet zijn gedefinieerd in broncode, is het mogelijk dat probleemoplossing inspectie van de tussenliggende taalcode (IL) vereist.
- De aanwezigheid van een statische constructor voorkomt dat het kenmerk van het BeforeFieldInit type wordt toegevoegd. Hierdoor wordt runtime-optimalisatie beperkt.
- Een veld dat als
static readonly
zodanig is gedeclareerd, kan alleen worden toegewezen als onderdeel van de declaratie of in een statische constructor. Wanneer een expliciete statische constructor niet is vereist, initialiseert u statische velden bij declaratie in plaats van via een statische constructor voor betere runtime-optimalisatie. - De runtime roept een statische constructor niet meer dan één keer aan in één toepassingsdomein. Deze aanroep wordt uitgevoerd in een vergrendelde regio op basis van het specifieke type klasse. Er zijn geen extra vergrendelingsmechanismen nodig in de hoofdtekst van een statische constructor. Als u het risico op impasses wilt voorkomen, blokkeert u de huidige thread niet in statische constructors en initializers. Wacht bijvoorbeeld niet op taken, threads, wachtgrepen of gebeurtenissen, verwerf geen vergrendelingen en voer geen blokkeringsbewerkingen uit, zoals parallelle lussen en
Parallel.Invoke
Parallelle LINQ-query's.
Notitie
Hoewel deze niet rechtstreeks toegankelijk is, moet de aanwezigheid van een expliciete statische constructor worden gedocumenteerd om u te helpen bij het oplossen van initialisatie-uitzonderingen.
Gebruik
- Een typisch gebruik van statische constructors is wanneer de klasse een logboekbestand gebruikt en de constructor wordt gebruikt om vermeldingen naar dit bestand te schrijven.
- Statische constructors zijn ook handig bij het maken van wrapperklassen voor onbeheerde code, wanneer de constructor de
LoadLibrary
methode kan aanroepen. - Statische constructors zijn ook een handige plek om runtimecontroles af te dwingen op de typeparameter die niet tijdens het compileren kan worden gecontroleerd via typeparameterbeperkingen.
Opmerking
In dit voorbeeld heeft de klasse Bus
een statische constructor. Wanneer het eerste exemplaar van Bus
wordt gemaakt (bus1
), wordt de statische constructor aangeroepen om de klasse te initialiseren. De voorbeelduitvoer controleert of de statische constructor slechts één keer wordt uitgevoerd, ook al worden er twee exemplaren van Bus
gemaakt en wordt deze uitgevoerd voordat de instantieconstructor wordt uitgevoerd.
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.
*/
C#-taalspecificatie
Zie de sectie Statische constructors van de C#-taalspecificatie voor meer informatie.