Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
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 eenOrders
eigenschap die een grote reeksOrder
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 hetOrders
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.