Lazy<T> Lazy<T> Lazy<T> Lazy<T> Class

定義

遅延初期化のサポートを提供します。

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

型パラメーター

T

遅延初期化されているオブジェクトの型。

継承
Lazy<T>Lazy<T>Lazy<T>Lazy<T>
派生
属性

次の例では、使用、Lazy<T>複数のスレッドからのアクセス権を持つ遅延初期化を提供するクラス。

注意

この例では、Lazy<T>(Func<T>)コンス トラクター。 使用にも示しますが、Lazy<T>(Func<T>, Boolean)コンス トラクター (を指定するtrueisThreadSafe) とLazy<T>(Func<T>, LazyThreadSafetyMode)コンス トラクター (を指定するLazyThreadSafetyMode.ExecutionAndPublicationmode)。 別のコンス トラクターを切り替えるだけどのコンス トラクターをコメント アウトを変更します。

例外を示す例については、同じコンス トラクターを使用して、キャッシュを参照してください、Lazy<T>(Func<T>)コンス トラクター。

この例では、複数あるスレッドのうちの 1 つによって遅れて初期化される LargeObject クラスを定義します。 コードの 4 つの主要セクションが、初期化子、ファクトリ メソッド、実際の初期化のコンス トラクターの作成を示しています、LargeObjectクラスは、オブジェクトが作成されたときにメッセージが表示されます。 Main メソッドの開始時に、この例では LargeObject のスレッドセーフな遅延初期化子が作成されます。

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);
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<LargeObject>(InitLargeObject, true);
'lazyLargeObject = new Lazy<LargeObject>(InitLargeObject, _
'                               LazyThreadSafetyMode.ExecutionAndPublication);

ファクトリ メソッドは、初期化を行うためのプレース ホルダーで、オブジェクトの作成を示しています。

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

次に示すように、最初の 2 つのコードのセクションでは、でしたラムダ関数を使用して組み合わせることを確認してください。

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

例では、遅延初期化が発生する前に、不確定な期間が切れることを示すために一時停止します。 押したときに、 Enterキー、例では、作成して 3 つのスレッドを開始します。 ThreadProc 3 つのスレッドのすべての呼び出しで使用されるメソッド、Valueプロパティ。 これは、最初に、LargeObjectインスタンスが作成されます。

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]);
}
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

コンス トラクター、LargeObjectクラスは、コードの最後の主要セクションが含まれているメッセージが表示され、初期化中のスレッドの id を記録します。 完全なコード リストの最後に、プログラムからの出力が表示されます。

int initBy = 0;
public LargeObject(int initializedBy)
{
    initBy = initializedBy;
    Console.WriteLine("LargeObject was created on thread id {0}.", 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

注意

簡略化のために、この例では Lazy<T> のグローバル インスタンスを使用して、すべてのメソッドは static (Visual Basic の Shared) です。 これらは、遅延初期化を使用するための要件ではありません。

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
 */
Imports System
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<LargeObject>(InitLargeObject, true);
        'lazyLargeObject = new Lazy<LargeObject>(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
' 

注釈

遅延初期化を使用して、このような作成または実行は、プログラムの有効期間中に発生しない場合に特に、大規模またはリソースを消費するオブジェクトの作成や、リソースを消費するタスクの実行を延期します。

インスタンスを作成する遅延初期化の準備として、Lazy<T>します。 型引数、Lazy<T>を作成するオブジェクトを遅延初期化に使用オブジェクトの種類を指定します。 使用して作成するコンス トラクター、Lazy<T>オブジェクトが初期化の特性を決定します。 遅延初期化は、Lazy<T>.Value プロパティへの初回のアクセス時に発生します。

ほとんどの場合、コンス トラクターを選択することは、2 つの質問に対する回答に依存します。

  • 遅れて初期化されるオブジェクトは、複数のスレッドからアクセスされるでしょうか。 そうである場合、Lazy<T>オブジェクトを使用するとすべてのスレッドで作成可能性があります。 既定の動作がスレッド セーフを作成するには単純なコンス トラクターのいずれかを使用することができますLazy<T>オブジェクト、それにアクセスしようとしているスレッドの数に関係なく遅延インスタンス化されたオブジェクトの 1 つのインスタンスが作成されます。 作成する、Lazy<T>スレッド セーフでないオブジェクトの場合は、スレッド セーフを含まないように指定することができるコンス トラクターを使用する必要があります。

    注意事項

    作成、Lazy<T>遅れて初期化されるオブジェクトはスレッド セーフでオブジェクトは保護されません。 複数のスレッドが遅れて初期化されるオブジェクトにアクセスできる場合おく必要がありますプロパティとメソッドのアクセスをマルチ スレッド セーフです。

  • 遅延初期化は、多くのコードを必要または遅れて初期化されるオブジェクトが既定のコンス トラクターにする必要があるし、例外をスローせず、あらゆる操作を実行しますか。 初期化コードを記述する必要がある場合、または例外を処理する必要がある場合は、ファクトリ メソッドを受け取るコンス トラクターのいずれかを使用します。 ファクトリ メソッドでは、初期化コードを記述します。

これら 2 つの要因に基づいて選択するにはコンス トラクターを次の表に示します。

オブジェクトがアクセスします。 初期化コードが必要ない場合 (既定のコンス トラクター) を使用して、 初期化コードが必要な場合は、使用します。
複数のスレッド Lazy<T>() Lazy<T>(Func<T>)
1 つのスレッド Lazy<T>(Boolean) isThreadSafe設定falseします。 Lazy<T>(Func<T>, Boolean) isThreadSafe設定falseします。

ラムダ式を使用すると、ファクトリ メソッドを指定します。 これにより、1 か所ですべての初期化コードが保持されます。 ラムダ式は、遅れて初期化されるオブジェクトのコンス トラクターに渡す引数も含めて、コンテキストをキャプチャします。

例外キャッシュファクトリ メソッドを使用する場合、例外がキャッシュされます。 つまり、ファクトリ メソッドが、例外の最初の時間をスローした場合、スレッドにアクセスしようと、Valueのプロパティ、Lazy<T>オブジェクトのすべての後続の試行で同じ例外がスローされます。 これにより、すべての呼び出し、Valueプロパティは同じ結果に、別のスレッドが異なる結果を取得する場合に生じる可能性のある微妙なエラーを回避できます。 Lazy<T> 、実際の代わりにTをそれ以外の場合は初期化されている以前の時点でスタートアップ中に通常します。 以前の時点のエラーでは、通常は致命的です。 回復可能なエラーが発生する可能性がある場合は、遅延初期化を使用していない場合と同様、(この例では、ファクトリ メソッド) で初期化ルーチンに再試行ロジックを作成することをお勧めします。

ロックする代わりに特定の状況でのオーバーヘッドを回避する可能性があります、Lazy<T>オブジェクトの既定のロック動作します。 まれに、デッドロックの可能性があります。 このような場合は、使用することができます、Lazy<T>(LazyThreadSafetyMode)またはLazy<T>(Func<T>, LazyThreadSafetyMode)コンス トラクターを指定してLazyThreadSafetyMode.PublicationOnlyします。 これにより、 Lazy<T> 、スレッドを呼び出す場合、それぞれ複数のスレッドの遅れて初期化されるオブジェクトのコピーを作成するオブジェクト、Valueプロパティ同時にします。 Lazy<T>オブジェクトにより、すべてのスレッドが遅れて初期化されるオブジェクトの同じインスタンスを使用し、使用されていないインスタンスを破棄します。 そのため、ロックのオーバーヘッドを軽減するのコストは、プログラムの作成し、負荷の高いオブジェクトの余分なコピーを破棄する場合がある場合がありますです。 ほとんどの場合でない可能性があります。 例では、Lazy<T>(LazyThreadSafetyMode)Lazy<T>(Func<T>, LazyThreadSafetyMode)コンス トラクターは、この動作を示します。

重要

指定するとLazyThreadSafetyMode.PublicationOnly、ファクトリ メソッドを指定した場合でも、例外はキャッシュされないされます。

同等のコンス トラクターの使用を有効にするだけでなくLazyThreadSafetyMode.PublicationOnlyLazy<T>(LazyThreadSafetyMode)Lazy<T>(Func<T>, LazyThreadSafetyMode)コンス トラクターは、他のコンス トラクターの機能を実現できます。 次の表では、同等の動作を生成するパラメーターの値を示します。

作成する、Lazy<T>されるオブジェクト コンス トラクターを持つ、 LazyThreadSafetyMode modeパラメーター設定mode ブール値を持つコンス トラクターのisThreadSafeパラメーター設定isThreadSafe スレッド セーフ パラメーターなしのコンス トラクター
完全スレッド セーフであります。使用がロックを 1 つのスレッドが値を初期化することを確認します。 ExecutionAndPublication true このようなすべてのコンス トラクターは、完全にスレッド セーフです。
スレッド セーフでないです。 None false 該当なし。
完全スレッド セーフであります。値を初期化するためにスレッド競合します。 PublicationOnly 該当なし。 該当なし。

その他の機能の使用についてはLazy<T>、スレッド内静的フィールドを持つ、またはプロパティのバッキング ストアとしてを参照してください。遅延初期化します。

コンストラクター

Lazy<T>() Lazy<T>() Lazy<T>() Lazy<T>()

Lazy<T> クラスの新しいインスタンスを初期化します。 遅延初期化が発生した場合は、ターゲット型の既定のコンストラクターが使用されます。

Lazy<T>(Boolean) Lazy<T>(Boolean) Lazy<T>(Boolean) Lazy<T>(Boolean)

Lazy<T> クラスの新しいインスタンスを初期化します。 遅延初期化が発生すると、ターゲット型の既定のコンストラクターおよび指定した初期化モードが使用されます。

Lazy<T>(Func<T>) Lazy<T>(Func<T>) Lazy<T>(Func<T>) Lazy<T>(Func<T>)

Lazy<T> クラスの新しいインスタンスを初期化します。 遅延初期化が発生すると、指定された初期化関数が使用されます。

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

Lazy<T> クラスの新しいインスタンスを初期化します。 遅延初期化が発生すると、指定された初期化関数と初期化モードが使用されます。

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

指定された初期化関数とスレッド セーフ モードを使用する Lazy<T> クラスの新しいインスタンスを初期化します。

Lazy<T>(LazyThreadSafetyMode) Lazy<T>(LazyThreadSafetyMode) Lazy<T>(LazyThreadSafetyMode) Lazy<T>(LazyThreadSafetyMode)

T の既定のコンストラクターと指定されたスレッド セーフ モードを使用する Lazy<T> クラスの新しいインスタンスを初期化します。

Lazy<T>(T) Lazy<T>(T) Lazy<T>(T) Lazy<T>(T)

事前に初期化され、指定された値を使用する Lazy<T> クラスの新しいインスタンスを初期化します。

プロパティ

IsValueCreated IsValueCreated IsValueCreated IsValueCreated

この Lazy<T> インスタンスに対して値が作成されているかどうかを示す値を取得します。

Value Value Value Value

現在の Lazy<T> インスタンスの遅れて初期化される値を取得します。

メソッド

Equals(Object) Equals(Object) Equals(Object) Equals(Object)

指定したオブジェクトが、現在のオブジェクトと等しいかどうかを判断します。

(Inherited from Object)
GetHashCode() GetHashCode() GetHashCode() GetHashCode()

既定のハッシュ関数として機能します。

(Inherited from Object)
GetType() GetType() GetType() GetType()

現在のインスタンスの Type を取得します。

(Inherited from Object)
MemberwiseClone() MemberwiseClone() MemberwiseClone() MemberwiseClone()

現在の Object の簡易コピーを作成します。

(Inherited from Object)
ToString() ToString() ToString() ToString()

このインスタンスの Value プロパティの文字列形式を作成して返します。

適用対象

スレッド セーフ

既定ですべてのパブリックおよびプロテクト メンバーのLazy<T>クラスはスレッド セーフであると、複数のスレッドから同時に使用される可能性があります。 これらのスレッド セーフの保証は、必要に応じて、型のコンス トラクターにパラメーターを使用して、インスタンスごとに削除できます。

こちらもご覧ください