Delen via


Luie initialisatie

Luie initialisatie van een object betekent dat het maken ervan wordt uitgesteld totdat het voor het eerst wordt gebruikt. (Voor dit onderwerp zijn de termen luie initialisatie en luie instantiëring synoniem.) Luie initialisatie wordt voornamelijk gebruikt om de prestaties te verbeteren, verspilling van berekeningen te voorkomen en geheugenvereisten voor programma's te verminderen. Dit zijn de meest voorkomende scenario's:

  • Wanneer u een object hebt dat duur is om te maken en het programma dit mogelijk niet gebruikt. Stel dat u een object in het geheugen Customer hebt met een Orders eigenschap die een grote reeks Order objecten bevat die, om te worden geïnitialiseerd, een databaseverbinding vereist. Als de gebruiker nooit vraagt om de orders weer te geven of de gegevens in een berekening te gebruiken, is er geen reden om systeemgeheugen of rekencycli te gebruiken om deze te maken. Lazy<Orders> Door het Orders object te declareren voor luie initialisatie, kunt u voorkomen dat systeembronnen worden weggespild wanneer het object niet wordt gebruikt.

  • Wanneer u een object hebt dat duur is om te maken en u het maken ervan wilt uitstellen totdat andere dure bewerkingen zijn voltooid. Stel dat uw programma meerdere objectexemplaren laadt wanneer het wordt gestart, maar slechts enkele exemplaren zijn onmiddellijk vereist. U kunt de opstartprestaties van het programma verbeteren door initialisatie van de objecten uit te stellen die niet vereist zijn totdat de vereiste objecten zijn gemaakt.

Hoewel u uw eigen code kunt schrijven om luie initialisatie uit te voeren, raden we u aan in plaats daarvan te gebruiken Lazy<T> . Lazy<T> en de bijbehorende typen ondersteunen ook thread-veiligheid en bieden een consistent doorgiftebeleid voor uitzonderingen.

De volgende tabel bevat de typen die .NET Framework versie 4 biedt voor het inschakelen van luie initialisatie in verschillende scenario's.

Typologie Beschrijving
Lazy<T> Een wrapper-klasse die luie initialisatiesemantiek biedt voor elk klassebibliotheek of door de gebruiker gedefinieerd type.
ThreadLocal<T> Lazy<T> Lijkt erop, behalve dat het luie initialisatie-semantiek biedt op basis van thread-local. Elke thread heeft toegang tot een eigen unieke waarde.
LazyInitializer Biedt geavanceerde static (Shared in Visual Basic) methoden voor luie initialisatie van objecten zonder overhead van een klasse.

Eenvoudige luie initialisatie

Als u een lui geïnitialiseerd type wilt definiëren, bijvoorbeeld MyType, gebruikt u Lazy<MyType> (Lazy(Of MyType) in Visual Basic), zoals wordt weergegeven in het volgende voorbeeld. Als er geen gemachtigde wordt meegestuurd naar de Lazy<T> constructor, wordt het omhulde type geconstrueerd met Activator.CreateInstance wanneer de waarde-eigenschap voor het eerst wordt aangeroepen. Als het type geen parameterloze constructor heeft, wordt er een runtime-uitzondering gegenereerd.

In het volgende voorbeeld wordt ervan uitgegaan dat dit Orders een klasse is die een matrix met Order objecten bevat die zijn opgehaald uit een database. Een Customer object bevat een exemplaar van Orders, maar afhankelijk van gebruikersacties zijn de gegevens van het Orders object mogelijk niet vereist.

// Initialize by using default Lazy<T> constructor. The
// Orders array itself is not created yet.
Lazy<Orders> _orders = new();
' Initialize by using default Lazy<T> constructor. The 
'Orders array itself is not created yet.
Dim _orders As Lazy(Of Orders) = New Lazy(Of Orders)()

U kunt ook een delegate doorgeven in de Lazy<T>-constructor die bij het aanmaken van het verpakte type een specifieke overload van de constructor aanroept en eventuele andere vereiste initialisatiestappen uitvoert, zoals weergegeven in het volgende voorbeeld.

// Initialize by invoking a specific constructor on Order when Value
// property is accessed
Lazy<Orders> _orders = new(() => new Orders(100));
' Initialize by invoking a specific constructor on Order 
' when Value property is accessed
Dim _orders As Lazy(Of Orders) = New Lazy(Of Orders)(Function() New Orders(100))

Nadat het Lazy-object is gemaakt, wordt er pas een exemplaar van Orders gemaakt als de eigenschap Value van de Lazy-variabele voor het eerst wordt gebruikt. Bij de eerste toegang wordt een verpakt type gemaakt, geretourneerd en vervolgens opgeslagen voor toekomstig gebruik.

// We need to create the array only if displayOrders is true
if (s_displayOrders == true)
{
    DisplayOrders(_orders.Value.OrderData);
}
else
{
    // Don't waste resources getting order data.
}
' We need to create the array only if _displayOrders is true
If _displayOrders = True Then
    DisplayOrders(_orders.Value.OrderData)
Else
    ' Don't waste resources getting order data.
End If

Een Lazy<T> object retourneert altijd hetzelfde object of dezelfde waarde waarmee het is geïnitialiseerd. Daarom is de Value eigenschap alleen-lezen. Als Value een verwijzingstype opslaat, kunt u er geen nieuw object aan toewijzen. (U kunt echter de waarde van de ingestelde openbare velden en eigenschappen wijzigen.) Als Value een waardetype wordt opgeslagen, kunt u de waarde ervan niet wijzigen. U kunt echter een nieuwe variabele maken door de variabeleconstructor opnieuw aan te roepen met behulp van nieuwe argumenten.

_orders = new Lazy<Orders>(() => new Orders(10));
_orders = New Lazy(Of Orders)(Function() New Orders(10))

De nieuwe luie instantie, zoals de vorige instantie, instantieert pas Orders wanneer Value de eigenschap voor het eerst wordt geopend.

Thread-veilige initialisatie

Standaard zijn Lazy<T> objecten thread-safe. Als de constructor niet opgeeft welk soort threadveiligheid van toepassing is, zijn de Lazy<T> objecten die hij creëert thread-safe. In scenario's met meerdere threads wordt de eerste thread voor toegang tot de Value eigenschap van een thread-veilig Lazy<T> object geïnitialiseerd voor alle volgende toegang tot alle threads en delen alle threads dezelfde gegevens. Daarom maakt het niet uit welke thread het object initialiseert en rasomstandigheden goedaardig zijn.

Notitie

U kunt deze consistentie uitbreiden naar foutvoorwaarden met uitzonderingscaching. Zie de volgende sectie uitzonderingen in Luie objecten voor meer informatie.

In het volgende voorbeeld ziet u dat hetzelfde Lazy<int> exemplaar dezelfde waarde heeft voor drie afzonderlijke threads.

// Initialize the integer to the managed thread id of the
// first thread that accesses the Value property.
Lazy<int> number = new(() => Environment.CurrentManagedThreadId);

Thread t1 = new(() => Console.WriteLine($"number on t1 = {number.Value} ThreadID = {Environment.CurrentManagedThreadId}"));
t1.Start();

Thread t2 = new(() => Console.WriteLine($"number on t2 = {number.Value} ThreadID = {Environment.CurrentManagedThreadId}"));
t2.Start();

Thread t3 = new(() => Console.WriteLine($"number on t3 = {number.Value} ThreadID = {Environment.CurrentManagedThreadId}"));
t3.Start();

// Ensure that thread IDs are not recycled if the
// first thread completes before the last one starts.
t1.Join();
t2.Join();
t3.Join();

/* Sample Output:
    number on t1 = 11 ThreadID = 11
    number on t3 = 11 ThreadID = 13
    number on t2 = 11 ThreadID = 12
    Press any key to exit.
*/
' Initialize the integer to the managed thread id of the 
' first thread that accesses the Value property.
Dim number As Lazy(Of Integer) = New Lazy(Of Integer)(Function()
                                                          Return Thread.CurrentThread.ManagedThreadId
                                                      End Function)

Dim t1 As New Thread(Sub()
                         Console.WriteLine("number on t1 = {0} threadID = {1}",
                                           number.Value, Thread.CurrentThread.ManagedThreadId)
                     End Sub)
t1.Start()

Dim t2 As New Thread(Sub()
                         Console.WriteLine("number on t2 = {0} threadID = {1}",
                                           number.Value, Thread.CurrentThread.ManagedThreadId)
                     End Sub)
t2.Start()

Dim t3 As New Thread(Sub()
                         Console.WriteLine("number on t3 = {0} threadID = {1}",
                                           number.Value, Thread.CurrentThread.ManagedThreadId)
                     End Sub)
t3.Start()

' Ensure that thread IDs are not recycled if the 
' first thread completes before the last one starts.
t1.Join()
t2.Join()
t3.Join()

' Sample Output:
'       number on t1 = 11 ThreadID = 11
'       number on t3 = 11 ThreadID = 13
'       number on t2 = 11 ThreadID = 12
'       Press any key to exit.

Als u afzonderlijke gegevens voor elke thread nodig hebt, gebruikt u het ThreadLocal<T> type, zoals verderop in dit onderwerp wordt beschreven.

Sommige Lazy<T> constructors hebben een Booleaanse parameter die isThreadSafe wordt gebruikt om op te geven of de Value eigenschap wordt geopend vanuit meerdere threads. Als u van plan bent om toegang te krijgen tot de eigenschap vanaf slechts één thread, geeft u door false om een bescheiden prestatievoordeel te verkrijgen. Als u van plan bent om vanuit meerdere threads toegang te krijgen tot de eigenschap, geef dan true door om het Lazy<T>-exemplaar te instrueren om racevoorwaarden correct af te handelen waarin één thread tijdens de initialisatie een uitzondering werpt.

Sommige Lazy<T> constructors hebben een parameter met de LazyThreadSafetyMode naam mode. Deze constructors bieden een aanvullende threadveiligheidsmodus. In de volgende tabel ziet u hoe de threadveiligheid van een Lazy<T> object wordt beïnvloed door constructorparameters die threadveiligheid opgeven. Elke constructor heeft maximaal één dergelijke parameter.

Draadveiligheid van het object LazyThreadSafetyMode mode parameter Booleaanse isThreadSafe parameter Geen veiligheidsparameters voor threads
Volledig thread-veilig; slechts één thread tegelijk probeert de waarde te initialiseren. ExecutionAndPublication true Ja.
Niet veilig voor gelijktijdig gebruik. None false Niet van toepassing.
Volledig thread-veilig; threads wedijveren om de waarde te initialiseren. PublicationOnly Niet van toepassing. Niet van toepassing.

Zoals in de tabel wordt weergegeven, is het opgeven van LazyThreadSafetyMode.ExecutionAndPublication voor de mode-parameter hetzelfde als het opgeven van true voor de isThreadSafe-parameter, en het opgeven van LazyThreadSafetyMode.None is hetzelfde als het opgeven van false.

Zie voor meer informatie over wat Execution en Publication betekenen, LazyThreadSafetyMode.

Als u LazyThreadSafetyMode.PublicationOnly opgeeft, kunnen meerdere threads proberen het Lazy<T> exemplaar te initialiseren. Slechts één thread kan deze race winnen en alle andere threads ontvangen de waarde die is geïnitialiseerd door de geslaagde thread. Als er tijdens de initialisatie een uitzondering op een thread wordt gegenereerd, ontvangt die thread niet de waarde die is ingesteld door de geslaagde thread. Uitzonderingen worden niet in de cache opgeslagen, dus een volgende poging om toegang te krijgen tot de Value eigenschap kan leiden tot een geslaagde initialisatie. Dit verschilt van de manier waarop uitzonderingen worden behandeld in andere modi, die in de volgende sectie worden beschreven. Zie de LazyThreadSafetyMode opsomming voor meer informatie.

Uitzonderingen in luie objecten

Zoals eerder vermeld, retourneert een Lazy<T> object altijd hetzelfde object of dezelfde waarde waarmee het is geïnitialiseerd en is de Value eigenschap daarom alleen-lezen. Als u caching van uitzonderingen inschakelt, wordt deze onveranderbaarheid ook uitgebreid tot uitzonderingsgedrag. Als voor een luie-geïnitialiseerd object uitzonderingscache is ingeschakeld en er een uitzondering wordt gegenereerd van de initialisatiemethode wanneer de eigenschap voor het Value eerst wordt geopend, wordt dezelfde uitzondering gegenereerd bij elke volgende poging om toegang te krijgen tot de Value eigenschap. Met andere woorden, de constructor van het verpakte type wordt nooit opnieuw aangeroepen, zelfs in multithreaded scenario's. Daarom kan het Lazy<T> object geen uitzondering genereren voor één toegang en een waarde retourneren voor een volgende toegang.

Uitzonderingscaching is ingeschakeld wanneer u een System.Lazy<T> constructor gebruikt die een initialisatiemethode (valueFactory parameter) gebruikt, bijvoorbeeld wanneer u de Lazy(T)(Func(T))constructor gebruikt. Als de constructor ook een LazyThreadSafetyMode waarde (mode parameter) gebruikt, geeft u LazyThreadSafetyMode.ExecutionAndPublication op of LazyThreadSafetyMode.None. Als u een initialisatiemethode opgeeft, kunt u uitzonderingen in de cache opslaan voor deze twee modi. De initialisatiemethode kan heel eenvoudig zijn. Het kan bijvoorbeeld de parameterloze constructor aanroepen voor T: new Lazy<Contents>(() => new Contents(), mode) in C# of New Lazy(Of Contents)(Function() New Contents()) in Visual Basic. Als u een System.Lazy<T> constructor gebruikt die geen initialisatiemethode opgeeft, worden uitzonderingen die door de parameterloze constructor T worden gegenereerd, niet in de cache opgeslagen. Zie de LazyThreadSafetyMode opsomming voor meer informatie.

Notitie

Als u een Lazy<T> object maakt met de isThreadSafe constructorparameter ingesteld op false of de mode constructorparameter ingesteld op LazyThreadSafetyMode.None, moet u vanuit één thread toegang krijgen tot het Lazy<T> object of uw eigen synchronisatie voorzien. Dit geldt voor alle aspecten van het object, inclusief het opslaan van uitzonderingen in de cache.

Zoals vermeld in de vorige sectie, behandelen Lazy<T> objecten die zijn gemaakt door LazyThreadSafetyMode.PublicationOnly uitzonderingen anders. Met PublicationOnlykunnen meerdere threads concurreren om het Lazy<T> exemplaar te initialiseren. In dit geval worden uitzonderingen niet in de cache opgeslagen en kunnen pogingen om toegang te krijgen tot de Value eigenschap worden voortgezet totdat de initialisatie is geslaagd.

De volgende tabel geeft een overzicht van de wijze waarop de Lazy<T> constructors het cachebeheer van foutafhandeling reguleren.

Constructeur Thread-veiligheidsmodus Maakt gebruik van initialisatiemethode Uitzonderingen worden in de cache opgeslagen
Luie(T)() (ExecutionAndPublication) Nee Nee
Lazy(T)(Func(T)) (ExecutionAndPublication) Ja Ja
Luie(T)(Booleaanse waarde) True (ExecutionAndPublication) of false (None) Nee Nee
Luie(T)(Func(T), Booleaanse waarde True (ExecutionAndPublication) of false (None) Ja Ja
Lazy(T)(LazyThreadSafetyMode) Door de gebruiker opgegeven Nee Nee
Lazy(T)(Func(T), LazyThreadSafetyMode) Door de gebruiker opgegeven Ja Nee als de gebruiker opgeeft PublicationOnly; anders, ja.

Een luie geïnitialiseerde eigenschap implementeren

Als u een openbare eigenschap wilt implementeren met behulp van luie initialisatie, definieert u het backingveld van de eigenschap als een Lazy<T> en retourneert u de Value eigenschap via de get accessor van de eigenschap.

class Customer
{
    private readonly Lazy<Orders> _orders;
    public string CustomerID { get; private set; }
    public Customer(string id)
    {
        CustomerID = id;
        _orders = new Lazy<Orders>(() =>
        {
            // You can specify any additional
            // initialization steps here.
            return new Orders(CustomerID);
        });
    }

    public Orders MyOrders
    {
        get
        {
            // Orders is created on first access here.
            return _orders.Value;
        }
    }
}
Class Customer
    Private _orders As Lazy(Of Orders)
    Public Shared CustomerID As String
    Public Sub New(ByVal id As String)
        CustomerID = id
        _orders = New Lazy(Of Orders)(Function()
                                          ' You can specify additional 
                                          ' initialization steps here
                                          Return New Orders(CustomerID)
                                      End Function)

    End Sub
    Public ReadOnly Property MyOrders As Orders

        Get
            Return _orders.Value
        End Get

    End Property

End Class

De Value eigenschap heeft het kenmerk Alleen-lezen. Daarom heeft de eigenschap die deze beschikbaar maakt geen set toegangsrechten. Als u een lees-/schrijfeigenschap nodig hebt die wordt ondersteund door een Lazy<T> object, moet de set toegangsfunctie een nieuw Lazy<T> object maken en dit toewijzen aan de opslagondersteuning. De set accessor moet een lambda-expressie maken die de nieuwe eigenschapswaarde retourneert die is doorgegeven aan de set accessor en die lambda-expressie doorgeven aan de constructor voor het nieuwe Lazy<T> object. De volgende toegang van de Value eigenschap zorgt voor initialisatie van de nieuwe Lazy<T>, waarna Value de eigenschap daarna de nieuwe waarde retourneert die aan de eigenschap is toegewezen. De reden voor deze ingewikkelde opstelling is het behouden van de ingebouwde multithreadingbescherming in Lazy<T>. Anders moeten de eigenschapstoegangsors de eerste waarde die door de Value eigenschap wordt geretourneerd, in de cache opslaan en alleen de waarde in de cache wijzigen en moet u hiervoor uw eigen threadveilige code schrijven. Vanwege de aanvullende initialisaties die vereist zijn voor een eigenschap lezen/schrijven die wordt ondersteund door een Lazy<T> object, zijn de prestaties mogelijk niet acceptabel. Bovendien kan, afhankelijk van het specifieke scenario, aanvullende coördinatie vereist zijn om racetoestanden tussen setters en getters te voorkomen.

Thread-lokale luie initialisatie

In sommige scenario's met meerdere threads wilt u mogelijk de eigen persoonlijke gegevens van elke thread geven. Dergelijke gegevens worden thread-locale gegevens genoemd. In .NET Framework versie 3.5 en eerder kunt u het ThreadStatic kenmerk toepassen op een statische variabele om deze thread-local te maken. Het gebruik van het ThreadStatic kenmerk kan echter leiden tot subtiele fouten. Zelfs eenvoudige initialisatie-instructies zorgen er bijvoorbeeld voor dat de variabele alleen wordt geïnitialiseerd op de eerste thread die deze opent, zoals wordt weergegeven in het volgende voorbeeld.

[ThreadStatic]
static int s_counter = 1;
<ThreadStatic()>
Shared counter As Integer

Op alle andere threads wordt de variabele geïnitialiseerd met behulp van de standaardwaarde (nul). Als alternatief in .NET Framework versie 4 kunt u het System.Threading.ThreadLocal<T> type gebruiken om een op exemplaren gebaseerde, thread-lokale variabele te maken die wordt geïnitialiseerd voor alle threads door de Action<T> gemachtigde die u opgeeft. In het volgende voorbeeld zullen alle threads die toegang tot counter hebben, de beginwaarde als zijnde 1 zien.

ThreadLocal<int> _betterCounter = new(() => 1);
Dim betterCounter As ThreadLocal(Of Integer) = New ThreadLocal(Of Integer)(Function() 1)

ThreadLocal<T> verpakt het object op ongeveer dezelfde manier als Lazy<T>, met deze essentiële verschillen:

  • Elke thread initialiseert de thread-lokale variabele met behulp van zijn eigen persoonlijke gegevens die niet toegankelijk zijn vanuit andere threads.

  • De ThreadLocal<T>.Value eigenschap is lezen/schrijven en kan elk gewenst aantal keren worden gewijzigd. Dit kan van invloed zijn op de doorgifte van uitzonderingen, bijvoorbeeld, één get bewerking kan een uitzondering veroorzaken, maar de volgende kan met succes de waarde initialiseren.

  • Als er geen initialisatiedelegatie is opgegeven, ThreadLocal<T> wordt het verpakte type geïnitialiseerd met behulp van de standaardwaarde van het type. In dit opzicht ThreadLocal<T> is dit consistent met het ThreadStaticAttribute kenmerk.

In het volgende voorbeeld ziet u dat elke thread die toegang heeft tot het ThreadLocal<int> exemplaar, een eigen unieke kopie van de gegevens krijgt.

// Initialize the integer to the managed thread id on a per-thread basis.
ThreadLocal<int> threadLocalNumber = new(() => Environment.CurrentManagedThreadId);
Thread t4 = new(() => Console.WriteLine($"threadLocalNumber on t4 = {threadLocalNumber.Value} ThreadID = {Environment.CurrentManagedThreadId}"));
t4.Start();

Thread t5 = new(() => Console.WriteLine($"threadLocalNumber on t5 = {threadLocalNumber.Value} ThreadID = {Environment.CurrentManagedThreadId}"));
t5.Start();

Thread t6 = new(() => Console.WriteLine($"threadLocalNumber on t6 = {threadLocalNumber.Value} ThreadID = {Environment.CurrentManagedThreadId}"));
t6.Start();

// Ensure that thread IDs are not recycled if the
// first thread completes before the last one starts.
t4.Join();
t5.Join();
t6.Join();

/* Sample Output:
   threadLocalNumber on t4 = 14 ThreadID = 14
   threadLocalNumber on t5 = 15 ThreadID = 15
   threadLocalNumber on t6 = 16 ThreadID = 16
*/
' Initialize the integer to the managed thread id on a per-thread basis.
Dim threadLocalNumber As New ThreadLocal(Of Integer)(Function() Thread.CurrentThread.ManagedThreadId)
Dim t4 As New Thread(Sub()
                         Console.WriteLine("number on t4 = {0} threadID = {1}",
                                           threadLocalNumber.Value, Thread.CurrentThread.ManagedThreadId)
                     End Sub)
t4.Start()

Dim t5 As New Thread(Sub()
                         Console.WriteLine("number on t5 = {0} threadID = {1}",
                                           threadLocalNumber.Value, Thread.CurrentThread.ManagedThreadId)
                     End Sub)
t5.Start()

Dim t6 As New Thread(Sub()
                         Console.WriteLine("number on t6 = {0} threadID = {1}",
                                           threadLocalNumber.Value, Thread.CurrentThread.ManagedThreadId)
                     End Sub)
t6.Start()

' Ensure that thread IDs are not recycled if the 
' first thread completes before the last one starts.
t4.Join()
t5.Join()
t6.Join()

'Sample(Output)
'      threadLocalNumber on t4 = 14 ThreadID = 14 
'      threadLocalNumber on t5 = 15 ThreadID = 15
'      threadLocalNumber on t6 = 16 ThreadID = 16 

Thread-lokale variabelen in Parallel.For en ForEach

Wanneer u de Parallel.For-methode of de Parallel.ForEach-methode gebruikt om over gegevensbronnen te itereren in parallel, kunt u de overbelastingen van functies met ingebouwde ondersteuning voor thread-locale data gebruiken. In deze methoden wordt de thread-localiteit bereikt door lokale gedelegeerden te gebruiken om de gegevens te creëren, openen en opschonen. Zie How to: Write a Parallel.For Loop with Thread-Local Variables en How to: Write a Parallel.ForEach Loop with Partition-Local Variables voor meer informatie.

Luie initialisatie gebruiken voor scenario's met lage overhead

In scenario's waarin u een groot aantal objecten moet lazy-initialiseren, kunt u besluiten dat het verpakken van elk object in een Lazy<T> te veel geheugen of te veel rekenresources vereist. Of misschien hebt u strenge vereisten over hoe luie initialisatie beschikbaar wordt gesteld. In dergelijke gevallen kunt u de static-methoden (Shared in Visual Basic) van de System.Threading.LazyInitializer-klasse gebruiken om elk object op een efficiënte manier te initialiseren zonder het in een exemplaar van Lazy<T> te verpakken.

In het volgende voorbeeld wordt ervan uitgegaan dat u, in plaats van een heel Orders object in één Lazy<T> object te verpakken, alleen lui-geïnitialiseerde afzonderlijke Order objecten hebt als ze nodig zijn.

// Assume that _orders contains null values, and
// we only need to initialize them if displayOrderInfo is true
if (displayOrderInfo == true)
{
    for (int i = 0; i < _orders.Length; i++)
    {
        // Lazily initialize the orders without wrapping them in a Lazy<T>
        LazyInitializer.EnsureInitialized(ref _orders[i], () =>
        {
            // Returns the value that will be placed in the ref parameter.
            return GetOrderForIndex(i);
        });
    }
}
' Assume that _orders contains null values, and
' we only need to initialize them if displayOrderInfo is true
If displayOrderInfo = True Then


    For i As Integer = 0 To _orders.Length
        ' Lazily initialize the orders without wrapping them in a Lazy(Of T)
        LazyInitializer.EnsureInitialized(_orders(i), Function()
                                                          ' Returns the value that will be placed in the ref parameter.
                                                          Return GetOrderForIndex(i)
                                                      End Function)
    Next
End If

In dit voorbeeld ziet u dat de initialisatieprocedure wordt aangeroepen bij elke iteratie van de lus. In scenario's met meerdere threads is de eerste thread voor het aanroepen van de initialisatieprocedure degene waarvan de waarde door alle threads wordt gezien. Latere threads roepen ook de initialisatieprocedure aan, maar hun resultaten worden niet gebruikt. Als dit soort potentiële raceconditie niet acceptabel is, gebruikt u de overbelasting van LazyInitializer.EnsureInitialized die een Booleaanse parameter en een synchronisatieobject neemt.

Zie ook