Bagikan melalui


Inisialisasi Malas

Inisialisasi malas objek berarti pembuatannya ditangguhkan hingga pertama kali digunakan. (Untuk topik ini, istilah inisialisasi malas dan instansiasi malas identik.) Inisialisasi malas terutama digunakan untuk meningkatkan performa, menghindari komputasi yang boros, dan mengurangi kebutuhan memori program. Berikut ini adalah skenario yang paling umum:

  • Jika Anda memiliki objek yang mahal untuk dibuat, dan program mungkin tidak menggunakannya. Misalnya, asumsikan bahwa Anda memiliki dalam memori objek Customer yang memiliki properti Orders yang berisi array objek Order yang, untuk diinisialisasi, memerlukan koneksi database. Jika pengguna tidak pernah meminta untuk menampilkan Pesanan atau menggunakan data dalam komputasi, tidak ada alasan untuk menggunakan memori sistem atau siklus komputasi untuk membuatnya. Dengan menggunakan Lazy<Orders> untuk mendeklarasikan objek Orders untuk inisialisasi malas, Anda dapat menghindari membuang-buang sumber daya sistem saat objek tidak digunakan.

  • Jika Anda memiliki objek yang mahal untuk dibuat, dan Anda ingin menunda pembuatannya hingga setelah operasi mahal lainnya selesai. Misalnya, asumsikan bahwa program Anda memuat beberapa instans objek saat dimulai, tetapi hanya beberapa di antaranya yang diperlukan segera. Anda dapat meningkatkan performa startup program dengan menunda inisialisasi objek yang tidak diperlukan hingga objek yang diperlukan telah dibuat.

Meskipun Anda dapat menulis kode Anda sendiri untuk melakukan inisialisasi malas, sebaiknya Anda menggunakan Lazy<T>. Lazy<T> dan jenis terkaitnya juga mendukung keamanan rangkaian dan memberikan kebijakan penyebaran pengecualian yang konsisten.

Tabel berikut mencantumkan jenis yang disediakan .NET Framework versi 4 untuk mengaktifkan inisialisasi malas dalam skenario yang berbeda.

Tipe Deskripsi
Lazy<T> Kelas pembungkus yang menyediakan semantik inisialisasi malas untuk pustaka kelas atau jenis yang ditentukan pengguna.
ThreadLocal<T> Menyerupai Lazy<T> kecuali ia menyediakan semantik inisialisasi malas berdasarkan rangkaian-lokal. Setiap rangkaian memiliki akses ke nilai uniknya sendiri.
LazyInitializer Menyediakan metode static (Shared dalam Visual Basic) tingkat lanjut untuk inisialisasi malas objek tanpa overhead kelas.

Inisialisasi Malas Dasar

Untuk menentukan jenis yang diinisialisasi malas, misalnya, MyType,gunakan Lazy<MyType> (Lazy(Of MyType) dalam Visual Basic), seperti yang ditunjukkan dalam contoh berikut. Jika tidak ada delegasi yang diteruskan dalam konstruktor Lazy<T>, jenis yang dibungkus dibuat dengan menggunakan Activator.CreateInstance saat properti nilai diakses pertama kali. Jika jenis tidak memiliki konstruktor tanpa parameter, pengecualian run-time akan muncul.

Dalam contoh berikut, asumsikan bahwa Orders adalah kelas yang berisi array objek Order yang diambil dari database. Objek Customer berisi instans Orders, tetapi tergantung pada tindakan pengguna, data dari objek Orders mungkin tidak diperlukan.

// Initialize by using default Lazy<T> constructor. The
// Orders array itself is not created yet.
Lazy<Orders> _orders = new Lazy<Orders>();
' 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)()

Anda juga dapat meneruskan delegasi di konstruktor Lazy<T> yang memanggil muatan berlebih konstruktor tertentu pada jenis yang dibungkus pada waktu pembuatan, dan melakukan langkah inisialisasi lain yang diperlukan, seperti yang ditunjukkan dalam contoh berikut.

// Initialize by invoking a specific constructor on Order when Value
// property is accessed
Lazy<Orders> _orders = new Lazy<Orders>(() => 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))

Setelah objek Malas dibuat, tidak ada instans Orders yang dibuat hingga properti Value variabel Malas diakses untuk pertama kalinya. Pada akses pertama, jenis yang dibungkus dibuat dan ditampilkan, dan disimpan untuk akses di masa mendatang.

// We need to create the array only if displayOrders is true
if (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

Objek Lazy<T> selalu menampilkan objek atau nilai yang sama dengan yang diinisialisasi. Oleh karena itu, properti Value bersifat baca-saja. Jika Value menyimpan jenis referensi, Anda tidak dapat menetapkan objek baru ke dalamnya. (Namun, Anda dapat mengubah nilai bidang dan properti publik yang dapat diatur.) Jika Value menyimpan jenis nilai, Anda tidak dapat mengubah nilainya. Namun demikian, Anda dapat membuat variabel baru dengan memanggil konstruktor variabel lagi dengan menggunakan argumen baru.

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

Instans malas baru, seperti yang sebelumnya, tidak membuat instans Orders hingga properti Value-nya diakses pertama kali.

Inisialisasi Bebas Rangkaian

Secara default, objek Lazy<T> bersifat bebas rangkaian. Yakni, jika konstruktor tidak menentukan jenis keamanan rangkaian, objek Lazy<T> yang dibuat bebas rangkaian. Dalam skenario multi-rangkaian, rangkaian pertama yang mengakses properti Value objek Lazy<T> bebas rangkaian menginisialisasinya untuk semua akses berikutnya di semua rangkaian, dan semua rangkaian berbagi data yang sama. Oleh karena itu, tidak masalah rangkaian mana yang menginisialisasi objek, dan kondisi balapan tidak berbahaya.

Catatan

Anda dapat memperluas konsistensi ini ke kondisi kesalahan dengan menggunakan penembolokan pengecualian. Untuk informasi selengkapnya, lihat bagian berikutnya, Pengecualian di Objek Malas.

Contoh berikut menunjukkan bahwa instans Lazy<int> yang sama memiliki nilai yang sama untuk tiga rangkaian terpisah.

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

Thread t1 = new Thread(() => Console.WriteLine("number on t1 = {0} ThreadID = {1}",
                                        number.Value, Thread.CurrentThread.ManagedThreadId));
t1.Start();

Thread t2 = new Thread(() => Console.WriteLine("number on t2 = {0} ThreadID = {1}",
                                        number.Value, Thread.CurrentThread.ManagedThreadId));
t2.Start();

Thread t3 = new Thread(() => Console.WriteLine("number on t3 = {0} ThreadID = {1}", number.Value,
                                        Thread.CurrentThread.ManagedThreadId));
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.

Jika Anda memerlukan data terpisah di setiap rangkaian, gunakan jenis ThreadLocal<T>, seperti yang dijelaskan nanti dalam topik ini.

Beberapa konstruktor Lazy<T> memiliki parameter Boolean bernama isThreadSafe yang digunakan untuk menentukan apakah properti Value akan diakses dari beberapa rangkaian. Jika Anda ingin mengakses properti hanya dari satu rangkaian, teruskan di false untuk mendapatkan manfaat performa yang sederhana. Jika Anda ingin mengakses properti dari beberapa rangkaian, teruskan di true untuk menginstruksikan instans Lazy<T> untuk menangani kondisi balapan dengan benar di mana satu rangkaian menampilkan pengecualian pada waktu inisialisasi.

Beberapa konstruktor Lazy<T> memiliki parameter LazyThreadSafetyMode bernama mode. Konstruktor ini menyediakan mode keamanan rangkaian tambahan. Tabel berikut menunjukkan bagaimana keamanan rangkaian objek Lazy<T> dipengaruhi oleh parameter konstruktor yang menentukan keamanan rangkaian. Setiap konstruktor memiliki maksimal satu parameter tersebut.

Keamanan rangkaian objek LazyThreadSafetyModemode parameter Parameter isThreadSafe Boolean Tidak ada parameter keamanan rangkaian
Sepenuhnya bebas rangkaian; hanya satu rangkaian pada satu waktu yang mencoba menginisialisasi nilai. ExecutionAndPublication true Ya.
Tidak bebas rangkaian. None false Tidak berlaku.
Sepenuhnya bebas rangkaian; balapan rangkaian untuk menginisialisasi nilai. PublicationOnly Tidak dapat diterapkan. Tidak dapat diterapkan.

Seperti yang ditunjukkan tabel, menentukan LazyThreadSafetyMode.ExecutionAndPublication untuk parameter mode sama dengan menentukan true untuk parameter isThreadSafe, dan menentukan LazyThreadSafetyMode.None sama dengan menentukan false.

Untuk informasi selengkapnya tentang apa yang dimaksud dengan Execution dan Publication, lihat LazyThreadSafetyMode.

Menentukan LazyThreadSafetyMode.PublicationOnly memungkinkan beberapa rangkaian untuk mencoba menginisialisasi instans Lazy<T>. Hanya satu rangkaian yang dapat memenangkan perlombaan ini, dan semua rangkaian lainnya menerima nilai yang diinsialisasi oleh rangkaian yang berhasil. Jika pengecualian muncul pada rangkaian selama inisialisasi, rangkaian tersebut tidak menerima nilai yang ditetapkan oleh rangkaian yang berhasil. Pengecualian tidak di-cache, sehingga upaya berikutnya untuk mengakses properti Value dapat mengakibatkan inisialisasi yang berhasil. Ini berbeda dengan cara pengecualian diperlakukan dalam mode lain, yang dijelaskan di bagian berikut. Untuk informasi selengkapnya, lihat enumerasi LazyThreadSafetyMode.

Pengecualian dalam Objek Malas

Seperti yang disebutkan sebelumnya, objek Lazy<T> selalu menampilkan objek atau nilai yang sama dengan yang diinisialisasi, dan oleh karena itu properti Value bersifat baca-saja. Jika Anda mengaktifkan penembolokan pengecualian, ketetapan ini juga meluas ke perilaku pengecualian. Jika objek yang diinisialisasi malas mengaktifkan penembolokan pengecualian dan menampilkan pengecualian dari metode inisialisasinya saat properti Value pertama kali diakses, pengecualian yang sama ditampilkan di setiap upaya berikutnya untuk mengakses properti Value. Dengan kata lain, konstruktor dari jenis yang dibungkus tidak pernah dipanggil kembali, bahkan dalam skenario multi-rangkaian. Oleh karena itu, objek Lazy<T> tidak dapat memunculkan pengecualian di satu akses dan menampilkan nilai di akses berikutnya.

Penembolokan pengecualian diaktifkan saat Anda menggunakan konstruktor System.Lazy<T> apa pun yang mengambil metode inisialisasi (parameter valueFactory); misalnya, ini diaktifkan saat Anda menggunakan konstruktor Lazy(T)(Func(T)). Jika konstruktor juga mengambil nilai LazyThreadSafetyMode (parameter mode), tentukan LazyThreadSafetyMode.ExecutionAndPublication atau LazyThreadSafetyMode.None. Menentukan metode inisialisasi memungkinkan penembolokan pengecualian untuk kedua mode ini. Metode inisialisasi bisa sangat sederhana. Misalnya, ini mungkin memanggil konstruktor tanpa parameter untuk T: new Lazy<Contents>(() => new Contents(), mode) di C#, atau New Lazy(Of Contents)(Function() New Contents()) di Visual Basic. Jika Anda menggunakan konstruktor System.Lazy<T> yang tidak menentukan metode inisialisasi, pengecualian yang ditampilkan oleh konstruktor tanpa parameter untuk T tidak di-cache. Untuk informasi selengkapnya, lihat enumerasi LazyThreadSafetyMode.

Catatan

Jika Anda membuat objek Lazy<T> dengan parameter konstruktor isThreadSafe yang diatur ke false atau parameter konstruktor mode diatur ke LazyThreadSafetyMode.None, Anda harus mengakses objek Lazy<T> dari satu rangkaian atau memberikan sinkronisasi Anda sendiri. Ini berlaku untuk semua aspek objek, termasuk penembolokan pengecualian.

Seperti yang disebutkan di bagian sebelumnya, objek Lazy<T> yang dibuat dengan menentukan LazyThreadSafetyMode.PublicationOnly memperlakukan pengecualian secara berbeda. Dengan PublicationOnly, beberapa rangkaian dapat bersaing untuk menginisialisasi instans Lazy<T>. Dalam hal ini, pengecualian tidak di-cache, dan upaya untuk mengakses properti Value dapat dilanjutkan hingga inisialisasi berhasil.

Tabel berikut ini meringkas cara konstruktor Lazy<T> mengontrol penembolokan pengecualian.

Konstruktor Mode keamanan rangkaian Menggunakan metode inisialisasi Pengecualian di-cache
Lazy(T)() Aku akan menemuinya.ExecutionAndPublication Tidak Tidak
Lazy(T)(Func(T)) Aku akan menemuinya.ExecutionAndPublication Ya Ya
Lazy(T)(Boolean) True (ExecutionAndPublication) atau false (None) Tidak Tidak
Lazy(T)(Func(T), Boolean) True (ExecutionAndPublication) atau false (None) Ya Ya
Lazy(T)(LazyThreadSafetyMode) Ditentukan pengguna Tidak Tidak
Lazy(T)(Func(T), LazyThreadSafetyMode) Ditentukan pengguna Ya Tidak jika pengguna menentukan PublicationOnly; jika tidak, ya.

Menerapkan Properti Inisialisasi Malas

Untuk mengimplementasikan properti publik dengan menggunakan inisialisasi malas, tentukan bidang pencadangan properti sebagai Lazy<T>, dan tampilkan properti Value dari pengakses get properti.

class Customer
{
    private 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(this.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

Properti Value bersifat baca-saja; oleh karena itu, properti yang mengeksposnya tidak memiliki pengakses set. Jika Anda memerlukan properti baca/tulis yang didukung oleh objek Lazy<T>, pengakses set harus membuat objek Lazy<T> baru dan menetapkannya ke penyimpanan cadangan. Pengakses set harus membuat ekspresi lambda yang menampilkan nilai properti baru yang diteruskan ke pengakses set, dan meneruskan ekspresi lambda tersebut ke konstruktor untuk objek Lazy<T> baru. Akses properti Value berikutnya akan menyebabkan inisialisasi Lazy<T> baru, dan setelah itu properti Value-nya akan menampilkan nilai baru yang ditetapkan ke properti. Alasan untuk pengaturan berbelit ini adalah untuk mempertahankan perlindungan multi-rangkaian yang dibangun ke dalam Lazy<T>. Jika tidak, pengakses properti harus menyimpan cache nilai pertama yang ditampilkan oleh properti Value dan hanya memodifikasi nilai yang di-cache, dan Anda harus menulis kode bebas rangkaian Anda sendiri untuk melakukannya. Karena inisialisasi tambahan yang diperlukan oleh properti baca/tulis yang didukung oleh objek Lazy<T>, performa mungkin tidak dapat diterima. Selain itu, tergantung pada skenario tertentu, koordinasi tambahan mungkin diperlukan untuk menghindari kondisi balapan antara setter dan getter.

Inisialisasi Malas Rangkaian Lokal

Dalam beberapa skenario multi-rangkaian, Anda mungkin ingin memberikan setiap rangkaian kepada data privatnya sendiri. Data ini disebut data rangkaian lokal. Di .NET Framework versi 3.5 dan versi sebelumnya, Anda dapat menerapkan atribut ThreadStatic ke variabel statik untuk menjadikannya rangkaian lokal. Namun, menggunakan atribut ThreadStatic dapat menyebabkan kesalahan yang tidak kentara. Misalnya, bahkan pernyataan inisialisasi dasar akan menyebabkan variabel diinisialisasi hanya pada rangkaian pertama yang mengaksesnya, seperti yang ditunjukkan dalam contoh berikut.

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

Pada semua rangkaian lainnya, variabel akan diinsialisasi dengan menggunakan nilai defaultnya (nol). Sebagai alternatif di .NET Framework versi 4, Anda dapat menggunakan jenis System.Threading.ThreadLocal<T> untuk membuat variabel berbasis instans rangkaian lokal yang diinisialisasi di semua rangkaian oleh delegasi Action<T> yang Anda sediakan. Dalam contoh berikut, semua rangkaian yang mengakses counter akan melihat nilai awalnya sebagai 1.

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

ThreadLocal<T> membungkus objeknya dengan cara yang sama persis seperti Lazy<T>, dengan perbedaan penting ini:

  • Setiap rangkaian menginisialisasi variabel rangkaian lokal dengan menggunakan data privatnya sendiri yang tidak dapat diakses dari rangkaian lain.

  • Properti ThreadLocal<T>.Value bersifat baca-tulis, dan dapat dimodifikasi berapa kali. Ini dapat memengaruhi penyebaran pengecualian, misalnya, satu operasi get dapat menampilkan pengecualian tetapi yang berikutnya berhasil menginisialisasi nilai.

  • Jika tidak ada delegasi inisialisasi yang disediakan, ThreadLocal<T> akan menginisialisasi jenisnya yang dibungkus dengan menggunakan nilai default jenis. Dalam hal ini, ThreadLocal<T> konsisten dengan atribut ThreadStaticAttribute.

Contoh berikut menunjukkan bahwa setiap rangkaian yang mengakses instans ThreadLocal<int> mendapatkan salinan data uniknya sendiri.

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

Thread t5 = new Thread(() => Console.WriteLine("threadLocalNumber on t5 = {0} ThreadID = {1}",
                                    threadLocalNumber.Value, Thread.CurrentThread.ManagedThreadId));
t5.Start();

Thread t6 = new Thread(() => Console.WriteLine("threadLocalNumber on t6 = {0} ThreadID = {1}",
                                    threadLocalNumber.Value, Thread.CurrentThread.ManagedThreadId));
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 

Variabel Rangkaian Lokal dalam Parallel.For dan ForEach

Saat Anda menggunakan metode Parallel.For atau metode Parallel.ForEach untuk melakukan perulangan sumber data secara paralel, Anda dapat menggunakan muatan berlebih yang memiliki dukungan bawaan untuk data rangkaian lokal. Dalam metode ini, lokalitas rangkaian dicapai dengan menggunakan delegasi lokal untuk membuat, mengakses, dan membersihkan data. Untuk informasi selengkapnya, lihat Cara: Menulis Perulangan Paralel.For Loop dengan Variabel Rangkaian Lokal dan Cara: Menulis Perulangan Parallel.ForEach dengan Variabel Partisi-Lokal.

Menggunakan Inisialisasi Malas untuk Skenario Muatan Berlebih Rendah

Dalam skenario di mana Anda harus melakukan inisialisasi malas sejumlah besar objek, Anda mungkin memutuskan bahwa membungkus setiap objek dalam Lazy<T> memerlukan terlalu banyak atau terlalu banyak sumber daya komputasi. Atau, Anda mungkin memiliki persyaratan ketat tentang bagaimana inisialisasi malas diekspos. Dalam kasus tersebut, Anda dapat menggunakan metode static (Shared dalam Visual Basic) kelas System.Threading.LazyInitializer untuk melakukan inisialisasi malas setiap objek tanpa membungkusnya dalam instans Lazy<T>.

Dalam contoh berikut, asumsikan bahwa, alih-alih membungkus seluruh objek Orders dalam satu objek Lazy<T>, Anda memiliki objek Order individual yang diinisialisasi malas hanya jika diperlukan.

// 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

Dalam contoh ini, perhatikan bahwa prosedur inisialisasi dipanggil di setiap pengulangan perulangan. Dalam skenario multi-rangkaian, rangkaian pertama yang memanggil prosedur inisialisasi adalah yang nilainya dilihat oleh semua rangkaian. Rangkaian berikutnya juga memanggil prosedur inisialisasi, tetapi hasilnya tidak digunakan. Jika kondisi balapan potensial semacam ini tidak dapat diterima, gunakan muatan berlebih LazyInitializer.EnsureInitialized yang menggunakan argumen Boolean dan objek sinkronisasi.

Lihat juga