Lazy<T> Sınıf

Tanım

Yavaş başlatma desteği sağlar.

generic <typename T>
public ref class Lazy
public class Lazy<T>
[System.Runtime.InteropServices.ComVisible(false)]
[System.Serializable]
public class Lazy<T>
type Lazy<'T> = class
[<System.Runtime.InteropServices.ComVisible(false)>]
[<System.Serializable>]
type Lazy<'T> = class
Public Class Lazy(Of T)

Tür Parametreleri

T

Yavaş başlatılmakta olan nesnenin türü.

Devralma
Lazy<T>
Türetilmiş
Öznitelikler

Örnekler

Aşağıdaki örnekte, birden çok iş parçacığından erişimle yavaş başlatma sağlamak için sınıfının kullanımı Lazy<T> gösterilmektedir.

Not

Örnekte oluşturucu kullanılır Lazy<T>(Func<T>) . Ayrıca oluşturucunun Lazy<T>(Func<T>, Boolean) (için isThreadSafebelirterek) ve oluşturucunun Lazy<T>(Func<T>, LazyThreadSafetyMode) (için modebelirterek true LazyThreadSafetyMode.ExecutionAndPublication) kullanımını da gösterir. Farklı bir oluşturucuya geçmek için açıklama satırı yapılan oluşturucuları değiştirmeniz gerekir.

Aynı oluşturucuları kullanarak özel durum önbelleğe almayı gösteren bir örnek için oluşturucuya Lazy<T>(Func<T>) bakın.

Örnek, birkaç iş parçacığından biri tarafından yavaş başlatılacak bir LargeObject sınıf tanımlar. Kodun dört önemli bölümü başlatıcının oluşturulmasını, fabrika yöntemini, gerçek başlatmayı ve nesne oluşturulduğunda bir ileti görüntüleyen sınıfın LargeObject oluşturucusunu gösterir. Yöntemin Main başında, örnek için LargeObjectiş parçacığı güvenli yavaş başlatıcıyı oluşturur:

lazyLargeObject = new Lazy<LargeObject>(InitLargeObject);

// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
//lazyLargeObject = new Lazy<LargeObject>(InitLargeObject, true);
//lazyLargeObject = new Lazy<LargeObject>(InitLargeObject,
//                               LazyThreadSafetyMode.ExecutionAndPublication);
let lazyLargeObject = Lazy<LargeObject> initLargeObject

// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
//     let lazyLargeObject = Lazy<LargeObject>(initLargeObject, true)
//     let lazyLargeObject = Lazy<LargeObject>(initLargeObject,
//                               LazyThreadSafetyMode.ExecutionAndPublication)
lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject)

' The following lines show how to use other constructors to achieve exactly the
' same result as the previous line: 
'lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, True)
'lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, _
'                               LazyThreadSafetyMode.ExecutionAndPublication)

Fabrika yöntemi, daha fazla başlatma için bir yer tutucu ile nesnesinin oluşturulmasını gösterir:

static LargeObject InitLargeObject()
{
    LargeObject large = new LargeObject(Thread.CurrentThread.ManagedThreadId);
    // Perform additional initialization here.
    return large;
}
let initLargeObject () =
    let large = LargeObject Thread.CurrentThread.ManagedThreadId
    // Perform additional initialization here.
    large
Private Shared Function InitLargeObject() As LargeObject
    Dim large As New LargeObject(Thread.CurrentThread.ManagedThreadId)
    ' Perform additional initialization here.
    Return large
End Function

İlk iki kod bölümünün burada gösterildiği gibi bir lambda işlevi kullanılarak birleştirilebileceğini unutmayın:

lazyLargeObject = new Lazy<LargeObject>(() =>
{
    LargeObject large = new LargeObject(Thread.CurrentThread.ManagedThreadId);
    // Perform additional initialization here.
    return large;
});
let lazyLargeObject = Lazy<LargeObject>(fun () ->
    let large = LargeObject Thread.CurrentThread.ManagedThreadId
    // Perform additional initialization here.
    large)
lazyLargeObject = New Lazy(Of LargeObject)(Function () 
    Dim large As New LargeObject(Thread.CurrentThread.ManagedThreadId) 
    ' Perform additional initialization here.
    Return large
End Function)

Gecikmeli başlatma gerçekleşmeden önce belirsiz bir sürenin geçebileceğini belirtmek için örnek duraklatılır. Enter tuşuna bastığınızda örnek üç iş parçacığı oluşturur ve başlatır. ThreadProc Üç iş parçacığı tarafından kullanılan yöntemi özelliğini çağırırValue. Bu ilk kez gerçekleştiğinde LargeObject örnek oluşturulur:

LargeObject large = lazyLargeObject.Value;

// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
//            object after creation. You must lock the object before accessing it,
//            unless the type is thread safe. (LargeObject is not thread safe.)
lock(large)
{
    large.Data[0] = Thread.CurrentThread.ManagedThreadId;
    Console.WriteLine("Initialized by thread {0}; last used by thread {1}.",
        large.InitializedBy, large.Data[0]);
}
let large = lazyLargeObject.Value

// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
//            object after creation. You must lock the object before accessing it,
//            unless the type is thread safe. (LargeObject is not thread safe.)
lock large (fun () ->
    large.Data[0] <- Thread.CurrentThread.ManagedThreadId
    printfn $"Initialized by thread {large.InitializedBy} last used by thread {large.Data[0]}.")
Dim large As LargeObject = lazyLargeObject.Value

' IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the  
'            object after creation. You must lock the object before accessing it,
'            unless the type is thread safe. (LargeObject is not thread safe.)
SyncLock large
    large.Data(0) = Thread.CurrentThread.ManagedThreadId
    Console.WriteLine("Initialized by thread {0}; last used by thread {1}.", _
        large.InitializedBy, large.Data(0))
End SyncLock

Kodun LargeObject son anahtar bölümünü içeren sınıfının oluşturucusunun bir ileti görüntüler ve başlatma iş parçacığının kimliğini kaydeder. Programın çıkışı, tam kod listesinin sonunda görüntülenir.

int initBy = 0;
public LargeObject(int initializedBy)
{
    initBy = initializedBy;
    Console.WriteLine("LargeObject was created on thread id {0}.", initBy);
}
type LargeObject(initBy) =
    do 
        printfn $"LargeObject was created on thread id %i{initBy}."
Private initBy As Integer = 0
Public Sub New(ByVal initializedBy As Integer)
    initBy = initializedBy
    Console.WriteLine("LargeObject was created on thread id {0}.", initBy)
End Sub

Not

Kolaylık olması için, bu örnekte genel bir örneği Lazy<T>kullanılır ve tüm yöntemler (Shared Visual Basic) şeklindedir static . Bunlar yavaş başlatmanın kullanılması için bir gereksinim değildir.

using System;
using System.Threading;

class Program
{
    static Lazy<LargeObject> lazyLargeObject = null;

    static LargeObject InitLargeObject()
    {
        LargeObject large = new LargeObject(Thread.CurrentThread.ManagedThreadId);
        // Perform additional initialization here.
        return large;
    }

    static void Main()
    {
        // The lazy initializer is created here. LargeObject is not created until the
        // ThreadProc method executes.
        lazyLargeObject = new Lazy<LargeObject>(InitLargeObject);

        // The following lines show how to use other constructors to achieve exactly the
        // same result as the previous line:
        //lazyLargeObject = new Lazy<LargeObject>(InitLargeObject, true);
        //lazyLargeObject = new Lazy<LargeObject>(InitLargeObject,
        //                               LazyThreadSafetyMode.ExecutionAndPublication);

        Console.WriteLine(
            "\r\nLargeObject is not created until you access the Value property of the lazy" +
            "\r\ninitializer. Press Enter to create LargeObject.");
        Console.ReadLine();

        // Create and start 3 threads, each of which uses LargeObject.
        Thread[] threads = new Thread[3];
        for (int i = 0; i < 3; i++)
        {
            threads[i] = new Thread(ThreadProc);
            threads[i].Start();
        }

        // Wait for all 3 threads to finish.
        foreach (Thread t in threads)
        {
            t.Join();
        }

        Console.WriteLine("\r\nPress Enter to end the program");
        Console.ReadLine();
    }

    static void ThreadProc(object state)
    {
        LargeObject large = lazyLargeObject.Value;

        // IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
        //            object after creation. You must lock the object before accessing it,
        //            unless the type is thread safe. (LargeObject is not thread safe.)
        lock(large)
        {
            large.Data[0] = Thread.CurrentThread.ManagedThreadId;
            Console.WriteLine("Initialized by thread {0}; last used by thread {1}.",
                large.InitializedBy, large.Data[0]);
        }
    }
}

class LargeObject
{
    public int InitializedBy { get { return initBy; } }

    int initBy = 0;
    public LargeObject(int initializedBy)
    {
        initBy = initializedBy;
        Console.WriteLine("LargeObject was created on thread id {0}.", initBy);
    }

    public long[] Data = new long[100000000];
}

/* This example produces output similar to the following:

LargeObject is not created until you access the Value property of the lazy
initializer. Press Enter to create LargeObject.

LargeObject was created on thread id 3.
Initialized by thread 3; last used by thread 3.
Initialized by thread 3; last used by thread 4.
Initialized by thread 3; last used by thread 5.

Press Enter to end the program
 */
open System
open System.Threading

type LargeObject(initBy) =
    do 
        printfn $"LargeObject was created on thread id %i{initBy}."
    member _.InitializedBy = initBy
    member val Data = Array.zeroCreate<int64> 100000000

let initLargeObject () =
    let large = LargeObject Thread.CurrentThread.ManagedThreadId
    // Perform additional initialization here.
    large

// The lazy initializer is created here. LargeObject is not created until the
// ThreadProc method executes.
let lazyLargeObject = Lazy<LargeObject> initLargeObject

// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
//     let lazyLargeObject = Lazy<LargeObject>(initLargeObject, true)
//     let lazyLargeObject = Lazy<LargeObject>(initLargeObject,
//                               LazyThreadSafetyMode.ExecutionAndPublication)

let threadProc (state: obj) =
    let large = lazyLargeObject.Value

    // IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
    //            object after creation. You must lock the object before accessing it,
    //            unless the type is thread safe. (LargeObject is not thread safe.)
    lock large (fun () ->
        large.Data[0] <- Thread.CurrentThread.ManagedThreadId
        printfn $"Initialized by thread {large.InitializedBy} last used by thread {large.Data[0]}.")

printfn """
LargeObject is not created until you access the Value property of the lazy
initializer. Press Enter to create LargeObject."""
stdin.ReadLine() |> ignore

// Create and start 3 threads, each of which uses LargeObject.

let threads = Array.zeroCreate 3
for i = 0 to 2 do
    threads[i] <- Thread(ParameterizedThreadStart threadProc)
    threads[i].Start()

// Wait for all 3 threads to finish.
for t in threads do
    t.Join()

printfn "\nPress Enter to end the program"
stdin.ReadLine() |> ignore

// This example produces output similar to the following:
//     LargeObject is not created until you access the Value property of the lazy
//     initializer. Press Enter to create LargeObject.
//     
//     LargeObject was created on thread id 3.
//     Initialized by thread 3 last used by thread 3.
//     Initialized by thread 3 last used by thread 4.
//     Initialized by thread 3 last used by thread 5.
//     
//     Press Enter to end the program
Imports System.Threading

Friend Class Program
    Private Shared lazyLargeObject As Lazy(Of LargeObject) = Nothing

    Private Shared Function InitLargeObject() As LargeObject
        Dim large As New LargeObject(Thread.CurrentThread.ManagedThreadId)
        ' Perform additional initialization here.
        Return large
    End Function


    Shared Sub Main()
        ' The lazy initializer is created here. LargeObject is not created until the 
        ' ThreadProc method executes.
        lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject)

        ' The following lines show how to use other constructors to achieve exactly the
        ' same result as the previous line: 
        'lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, True)
        'lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, _
        '                               LazyThreadSafetyMode.ExecutionAndPublication)


        Console.WriteLine(vbCrLf & _
            "LargeObject is not created until you access the Value property of the lazy" _
            & vbCrLf & "initializer. Press Enter to create LargeObject.")
        Console.ReadLine()

        ' Create and start 3 threads, each of which uses LargeObject.
        Dim threads(2) As Thread
        For i As Integer = 0 To 2
            threads(i) = New Thread(AddressOf ThreadProc)
            threads(i).Start()
        Next i

        ' Wait for all 3 threads to finish. 
        For Each t As Thread In threads
            t.Join()
        Next t

        Console.WriteLine(vbCrLf & "Press Enter to end the program")
        Console.ReadLine()
    End Sub


    Private Shared Sub ThreadProc(ByVal state As Object)
        Dim large As LargeObject = lazyLargeObject.Value

        ' IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the  
        '            object after creation. You must lock the object before accessing it,
        '            unless the type is thread safe. (LargeObject is not thread safe.)
        SyncLock large
            large.Data(0) = Thread.CurrentThread.ManagedThreadId
            Console.WriteLine("Initialized by thread {0}; last used by thread {1}.", _
                large.InitializedBy, large.Data(0))
        End SyncLock
    End Sub
End Class

Friend Class LargeObject
    Public ReadOnly Property InitializedBy() As Integer
        Get
            Return initBy
        End Get
    End Property

    Private initBy As Integer = 0
    Public Sub New(ByVal initializedBy As Integer)
        initBy = initializedBy
        Console.WriteLine("LargeObject was created on thread id {0}.", initBy)
    End Sub

    Public Data(99999999) As Long
End Class

' This example produces output similar to the following:
'
'LargeObject is not created until you access the Value property of the lazy
'initializer. Press Enter to create LargeObject.
'
'LargeObject was created on thread id 3.
'Initialized by thread 3; last used by thread 3.
'Initialized by thread 3; last used by thread 5.
'Initialized by thread 3; last used by thread 4.
'
'Press Enter to end the program
'

Açıklamalar

Özellikle programın kullanım ömrü boyunca böyle bir oluşturma veya yürütme gerçekleşemediğinde, büyük veya kaynak yoğunluklu bir nesnenin oluşturulmasını veya yoğun kaynak kullanan bir görevin yürütülmesini ertelemek için yavaş başlatmayı kullanın.

Yavaş başlatmaya hazırlanmak için bir örneği Lazy<T>oluşturursunuz. Oluşturduğunuz nesnenin Lazy<T> tür bağımsız değişkeni, yavaş başlatmak istediğiniz nesnenin türünü belirtir. Nesnesini oluşturmak Lazy<T> için kullandığınız oluşturucu, başlatmanın özelliklerini belirler. Gecikmeli başlatma özelliğine ilk kez Lazy<T>.Value erişildiğinde gerçekleşir.

Çoğu durumda, bir oluşturucu seçmek iki soruya yanıtlarınıza bağlıdır:

  • Yavaş başlatılan nesneye birden fazla iş parçacığından erişilecek mi? Öyleyse, Lazy<T> nesne herhangi bir iş parçacığında oluşturabilir. Varsayılan davranışı iş parçacığı güvenli Lazy<T> bir nesne oluşturmak olan basit oluşturuculardan birini kullanabilirsiniz; böylece, kaç iş parçacığı erişmeye çalışırsa çalışsın, lazily instantiated nesnesinin yalnızca bir örneği oluşturulur. İş parçacığı güvenli olmayan bir Lazy<T> nesne oluşturmak için, iş parçacığı güvenliği belirtmenizi sağlayan bir oluşturucu kullanmanız gerekir.

    Dikkat

    Nesne iş parçacığının Lazy<T> güvenli hale getirilmesi, yavaş başlatılan nesneyi korumaz. Birden çok iş parçacığı yavaş başlatılan nesneye erişebiliyorsa, özelliklerini ve yöntemlerini çok iş parçacıklı erişim için güvenli hale getirmeniz gerekir.

  • Yavaş başlatma çok fazla kod gerektiriyor mu yoksa yavaş başlatılan nesnenin ihtiyacınız olan her şeyi yapıp özel durumlar oluşturmayan parametresiz bir oluşturucuya sahip mi? Başlatma kodu yazmanız gerekiyorsa veya özel durumların işlenmesi gerekiyorsa, fabrika yöntemini alan oluşturuculardan birini kullanın. Başlatma kodunuzu fabrika yöntemine yazın.

Aşağıdaki tabloda, bu iki faktöre bağlı olarak hangi oluşturucunun seçileceği gösterilmektedir:

Nesneye şu şekilde erişilir: Başlatma kodu gerekmiyorsa (parametresiz oluşturucu) Başlatma kodu gerekiyorsa şunu kullanın:
Birden çok iş parçacığı Lazy<T>() Lazy<T>(Func<T>)
Bir iş parçacığı Lazy<T>(Boolean) olarak isThreadSafe ayarlanmış olarak falseayarlayın. Lazy<T>(Func<T>, Boolean) olarak isThreadSafe ayarlanmış olarak falseayarlayın.

Fabrika yöntemini belirtmek için bir lambda ifadesi kullanabilirsiniz. Bu, tüm başlatma kodunu tek bir yerde tutar. Lambda ifadesi, lazily initialized nesnesinin oluşturucusna geçirdiğiniz bağımsız değişkenler de dahil olmak üzere bağlamı yakalar.

Özel durum önbelleğe alma Fabrika yöntemlerini kullandığınızda özel durumlar önbelleğe alınır. Yani, bir iş parçacığı nesnenin özelliğine Lazy<T> ilk kez erişmeye Value çalıştığında fabrika yöntemi bir özel durum oluşturursa, sonraki her girişimde aynı özel durum oluşturulur. Bu, özelliğine yapılan her çağrının Value aynı sonucu üretmesini sağlar ve farklı iş parçacıkları farklı sonuçlar alırsa ortaya çıkabilecek küçük hataları önler. , Lazy<T> aksi takdirde genellikle başlatma sırasında daha önceki bir noktada başlatılmış olan bir gerçek T anlamına gelir. Bu önceki noktadaki bir hata genellikle önemli olur. Kurtarılabilir bir hata olasılığı varsa, yavaş başlatma kullanmadığınız durumlarda yaptığınız gibi yeniden deneme mantığını başlatma yordamına (bu örnekte fabrika yöntemi) derlemenizi öneririz.

Kilitlemeye alternatif Bazı durumlarda, nesnenin varsayılan kilitleme davranışının Lazy<T> ek yükünden kaçınmak isteyebilirsiniz. Nadir durumlarda kilitlenme olasılığı olabilir. Bu gibi durumlarda, veya oluşturucuyu Lazy<T>(LazyThreadSafetyMode) kullanabilir ve belirtebilirsinizLazyThreadSafetyMode.PublicationOnly.Lazy<T>(Func<T>, LazyThreadSafetyMode) Bu, iş parçacıkları özelliği aynı anda çağırırsa, nesnenin birkaç iş parçacığında yavaş başlatılan nesnenin bir kopyasını oluşturmasını Value sağlarLazy<T>. Lazy<T> nesnesi, tüm iş parçacıklarının lazily initialized nesnesinin aynı örneğini kullanmasını sağlar ve kullanılmayan örnekleri atar. Bu nedenle, kilitleme ek yükünü azaltmanın maliyeti, programınızın bazen pahalı bir nesnenin ek kopyalarını oluşturup atabileceğidir. Çoğu durumda, bu pek olası değildir. ve Lazy<T>(Func<T>, LazyThreadSafetyMode) oluşturucuları Lazy<T>(LazyThreadSafetyMode) için örnekler bu davranışı gösterir.

Önemli

belirttiğinizde LazyThreadSafetyMode.PublicationOnly, bir fabrika yöntemi belirtseniz bile özel durumlar hiçbir zaman önbelleğe alınmaz.

Eşdeğer oluşturucular ve oluşturucuları, kullanımını LazyThreadSafetyMode.PublicationOnlyLazy<T>(LazyThreadSafetyMode) Lazy<T>(Func<T>, LazyThreadSafetyMode) etkinleştirmeye ek olarak diğer oluşturucuların işlevlerini çoğaltabilir. Aşağıdaki tabloda, eşdeğer davranış üreten parametre değerleri gösterilmektedir.

Bir nesne oluşturmak Lazy<T> için Parametresi mode olan LazyThreadSafetyMode mode oluşturucular için Boole isThreadSafe parametresine isThreadSafe sahip oluşturucular için İş parçacığı güvenlik parametresi olmayan oluşturucular için
Tamamen iş parçacığı güvenli; yalnızca bir iş parçacığının değeri başlatmasını sağlamak için kilitlemeyi kullanır. ExecutionAndPublication true Tüm bu oluşturucular tamamen iş parçacığı güvenlidir.
İş parçacığı güvenli değil. None false Geçerli değildir.
Tamamen iş parçacığı güvenli; threads değeri başlatmak için yarışıyor. PublicationOnly Geçerli değildir. Geçerli değildir.

Diğer özellikler İş parçacığı statik alanlarıyla veya özellikler için yedekleme deposu olarak kullanımı Lazy<T> hakkında bilgi için bkz. Gecikmeli Başlatma.

Oluşturucular

Lazy<T>()

Lazy<T> sınıfının yeni bir örneğini başlatır. Gecikmeli başlatma gerçekleştiğinde, hedef türün parametresiz oluşturucu kullanılır.

Lazy<T>(Boolean)

Lazy<T> sınıfının yeni bir örneğini başlatır. Yavaş başlatma gerçekleştiğinde, hedef türün parametresiz oluşturucu ve belirtilen başlatma modu kullanılır.

Lazy<T>(Func<T>)

Lazy<T> sınıfının yeni bir örneğini başlatır. Gecikmeli başlatma gerçekleştiğinde, belirtilen başlatma işlevi kullanılır.

Lazy<T>(Func<T>, Boolean)

Lazy<T> sınıfının yeni bir örneğini başlatır. Gecikmeli başlatma gerçekleştiğinde, belirtilen başlatma işlevi ve başlatma modu kullanılır.

Lazy<T>(Func<T>, LazyThreadSafetyMode)

Belirtilen başlatma işlevini ve iş parçacığı güvenliği modunu kullanan sınıfının yeni bir örneğini Lazy<T> başlatır.

Lazy<T>(LazyThreadSafetyMode)

sınıfının parametresiz oluşturucuyu T ve belirtilen iş parçacığı güvenliği modunu kullanan yeni bir örneğini Lazy<T> başlatır.

Lazy<T>(T)

Önceden başlatılmamış belirtilen değeri kullanan sınıfının yeni bir örneğini Lazy<T> başlatır.

Özellikler

IsValueCreated

Bu Lazy<T> örnek için bir değer oluşturulup oluşturulmadığını belirten bir değer alır.

Value

Geçerli Lazy<T> örneğin lazily initialized değerini alır.

Yöntemler

Equals(Object)

Belirtilen nesnenin geçerli nesneye eşit olup olmadığını belirler.

(Devralındığı yer: Object)
GetHashCode()

Varsayılan karma işlevi işlevi görür.

(Devralındığı yer: Object)
GetType()

Type Geçerli örneğini alır.

(Devralındığı yer: Object)
MemberwiseClone()

Geçerli Objectöğesinin sığ bir kopyasını oluşturur.

(Devralındığı yer: Object)
ToString()

Bu örnek için özelliğinin dize gösterimini Value oluşturur ve döndürür.

Şunlara uygulanır

İş Parçacığı Güvenliği

Varsayılan olarak, sınıfın Lazy<T> tüm ortak ve korumalı üyeleri iş parçacığı güvenlidir ve birden çok iş parçacığından eşzamanlı olarak kullanılabilir. Bu iş parçacığı güvenliği garantileri, türün oluşturucularına yönelik parametreler kullanılarak isteğe bağlı olarak ve örnek başına kaldırılabilir.

Ayrıca bkz.