Dieser Artikel wurde maschinell übersetzt. Wenn Sie die englische Version des Artikels anzeigen möchten, aktivieren Sie das Kontrollkästchen Englisch. Sie können den englischen Text auch in einem Popupfenster anzeigen, indem Sie den Mauszeiger über den Text bewegen.
Übersetzung
Englisch

Lazy<T>-Konstruktor: (Func<T>, LazyThreadSafetyMode)

.NET Framework (current version)
 

Veröffentlicht: Oktober 2016

Initialisiert eine neue Instanz der Lazy<T>-Klasse, die die angegebene Initialisierungsfunktion und den angegebenen Threadsicherheitsmodus verwendet.

Namespace:   System
Assembly:  mscorlib (in mscorlib.dll)

public Lazy(
	Func<T> valueFactory,
	LazyThreadSafetyMode mode
)

Parameter

valueFactory
Type: System.Func<T>

Der Delegat, der aufgerufen wird, um bei Bedarf den verzögert initialisierten Wert zu erzeugen.

mode
Type: System.Threading.LazyThreadSafetyMode

Einer der Enumerationswerte, der den Threadsicherheitsmodus angibt.

Exception Condition
ArgumentOutOfRangeException

mode enthält einen ungültigen Wert.

ArgumentNullException

valueFactory ist null.

Die Thread-Sicherheitsmodus, der eine Lazy<T> -Instanz beschreibt das Verhalten, wenn mehrere Threads versuchen, initialisieren die Lazy<T> Instanz.

Durch ausgelöste Ausnahmen valueFactory zwischengespeichert werden, es sei denn, mode ist PublicationOnly. Weitere Informationen finden Sie unter der Lazy<T>-Klasse oder unter der System.Threading.LazyThreadSafetyMode-Enumeration.

Das folgende Beispiel veranschaulicht die Verwendung dieses Konstruktors eine verzögerte Initialisierung zu erstellen, die können mehrere Threads Rennen um ein Objekt verzögert zu erzeugen. Mehrere Threads möglicherweise bei der Erstellung von Instanzen erfolgreich, aber alle Threads verwenden, die Instanz, die erstellt wurde. Darüber hinaus veranschaulicht, dass Ausnahmen niemals zwischengespeichert werden, bei der Angabe PublicationOnly, selbst wenn die Initialisierung von einer Funktion nicht ausgeführt wird, vom Standardkonstruktor des Typs verzögert erstellt.

System_CAPS_noteHinweis

Ein Beispiel für die Verwendung dieses Konstruktors in Singlethread-Szenarios (Angeben von LazyThreadSafetyMode.None für mode), finden Sie unter der Lazy<T>(Boolean) Konstruktor. Ein Beispiel, das veranschaulicht, wie mithilfe dieses Konstruktors anstelle von Racebedingungen in Multithreadszenarien Sperren bereitstellen (Angeben von LazyThreadSafetyMode.ExecutionAndPublication für mode), finden Sie unter der Lazy<T>() Konstruktor.

Das Beispiel definiert eine LargeObject -Klasse, die von einer von mehreren Threads verzögert initialisiert wird. Die vier wichtigsten Abschnitte des Codes veranschaulichen die Erstellung der Initialisierer, die eigentliche Initialisierung, die Initialisierungsfunktion, und der Konstruktor und Finalizer, der die LargeObject Klasse. Am Anfang der Main -Methode, um das Beispiel erstellt die Lazy<T> -Objekt, das verzögerte Initialisierung von führt die LargeObject:

lazyLargeObject = new Lazy<LargeObject>(InitLargeObject, 
                             LazyThreadSafetyMode.PublicationOnly);

Die verzögerte Initialisierung verwendet die Funktion zum Ausführen der Initialisierung. In diesem Fall ist eine Funktion erforderlich, da es kein Standardkonstruktor für ist die LargeObject Klasse.

Das Beispiel erstellt und startet drei Threads, die blockiert ein ManualResetEvent Objekt, sodass das Beispiel die Threads gleichzeitig freigeben kann. In der ThreadProc -Methode, die von allen drei Threads Aufrufen verwendet wird, die Value Eigenschaft erstellt die LargeObject Instanz:

LargeObject large = null;
try
{
    large = lazyLargeObject.Value;

    // The following line introduces an artificial delay, to exaggerate the race 
    // condition.
    Thread.Sleep(5); 

    // 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("LargeObject was initialized by thread {0}; last used by thread {1}.", 
            large.InitializedBy, large.Data[0]);
    }
}
catch (ApplicationException ex)
{
    Console.WriteLine("ApplicationException: {0}", ex.Message);
}

In der dritten Abschnitt des Codes, die verzögerte Initialisierung-Funktion aufgerufen, um das Erstellen der LargeObject Instanz. Die Funktion löst eine Ausnahme beim ersten Mal aufgerufen wird:

static int instanceCount = 0;
static LargeObject InitLargeObject()
{
    if (1 == Interlocked.Increment(ref instanceCount))
    {
        throw new ApplicationException(
            String.Format("Lazy initialization function failed on thread {0}.",
            Thread.CurrentThread.ManagedThreadId));
    }
    return new LargeObject(Thread.CurrentThread.ManagedThreadId);
}

Mit anderen LazyThreadSafetyMode festlegen, würde eine nicht behandelte Ausnahme in der Initialisierungsfunktion zwischengespeichert werden. Allerdings PublicationOnly unterdrückt das Zwischenspeichern von Ausnahmen. Die Ausgabe des Beispiels zeigt, dass beim Initialisieren des Objekts ein weiteren Versuch erfolgreich ist.

System_CAPS_noteHinweis

Die Meldung zur Ausnahme tritt üblicherweise nach darauf hinweist, dass andere Threads das Objekt erfolgreich initialisiert wurden. Dies ist aufgrund der Verzögerung durch das Auslösen und Abfangen der Ausnahme.

Da der Konstruktor für die Lazy<T> angegebene Instanz LazyThreadSafetyMode.PublicationOnly, dürfen alle drei Threads erstellen LargeObject Instanzen. Das Beispiel veranschaulicht dies durch Konsole Nachrichten anzeigen, im Konstruktor und in der Finalize-Methode von der LargeObject Klasse:

public LargeObject(int initializedBy) 
{ 
    initBy = initializedBy;
    Console.WriteLine("Constructor: Instance initializing on thread {0}", initBy);
}

~LargeObject()
{
    Console.WriteLine("Finalizer: Instance was initialized on {0}", initBy);
}

Das Lazy<T> Objekt wird sichergestellt, dass nur eine Instanz von allen Threads (mit Ausnahme des Threads, wobei die Initialisierungsfunktion löst eine Ausnahme aus) verwendet wird. Die Ausgabe im Beispiel zeigt dies.

System_CAPS_noteHinweis

Der Einfachheit halber wird in diesem Beispiel eine globale Instanz von Lazy<T> verwendet, und alle Methoden sind static (Shared in Visual Basic). Dies sind keine Anforderungen für die Verwendung der verzögerten Initialisierung.

using System;
using System.Threading;

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

    // Factory function for lazy initialization.
    static int instanceCount = 0;
    static LargeObject InitLargeObject()
    {
        if (1 == Interlocked.Increment(ref instanceCount))
        {
            throw new ApplicationException(
                String.Format("Lazy initialization function failed on thread {0}.",
                Thread.CurrentThread.ManagedThreadId));
        }
        return new LargeObject(Thread.CurrentThread.ManagedThreadId);
    }

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


        // Create and start 3 threads, passing the same blocking event to all of them.
        ManualResetEvent startingGate = new ManualResetEvent(false);
        Thread[] threads = { new Thread(ThreadProc), new Thread(ThreadProc), new Thread(ThreadProc) };
        foreach (Thread t in threads)
        {
            t.Start(startingGate);
        }

        // Give all 3 threads time to start and wait, then release them all at once.
        Thread.Sleep(50);
        startingGate.Set();

        // Wait for all 3 threads to finish. (The order doesn't matter.)
        foreach (Thread t in threads)
        {
            t.Join();
        }

        Console.WriteLine(
            "\r\nThreads are complete. Running GC.Collect() to reclaim extra instances.");

        GC.Collect();

        // Allow time for garbage collection, which happens asynchronously.
        Thread.Sleep(100);

        Console.WriteLine("\r\nNote that only one instance of LargeObject was used.");
        Console.WriteLine("Press Enter to end the program");
        Console.ReadLine();
    }


    static void ThreadProc(object state)
    {
        // Wait for the signal.
        ManualResetEvent waitForStart = (ManualResetEvent) state;
        waitForStart.WaitOne();

        LargeObject large = null;
        try
        {
            large = lazyLargeObject.Value;

            // The following line introduces an artificial delay, to exaggerate the race 
            // condition.
            Thread.Sleep(5); 

            // 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("LargeObject was initialized by thread {0}; last used by thread {1}.", 
                    large.InitializedBy, large.Data[0]);
            }
        }
        catch (ApplicationException ex)
        {
            Console.WriteLine("ApplicationException: {0}", ex.Message);
        }
    }
}

class LargeObject
{
    int initBy = -1;
    public int InitializedBy { get { return initBy; } }

    public LargeObject(int initializedBy) 
    { 
        initBy = initializedBy;
        Console.WriteLine("Constructor: Instance initializing on thread {0}", initBy);
    }

    ~LargeObject()
    {
        Console.WriteLine("Finalizer: Instance was initialized on {0}", initBy);
    }

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

/* This example produces output similar to the following:

Constructor: Instance initializing on thread 5
Constructor: Instance initializing on thread 4
ApplicationException: Lazy initialization function failed on thread 3.
LargeObject was initialized by thread 5; last used by thread 5.
LargeObject was initialized by thread 5; last used by thread 4.

Threads are complete. Running GC.Collect() to reclaim extra instances.
Finalizer: Instance was initialized on 4

Note that only one instance of LargeObject was used.
Press Enter to end the program

Finalizer: Instance was initialized on 5
 */

Universelle Windows-Plattform
Verfügbar seit 8
.NET Framework
Verfügbar seit 4.0
Portierbare Klassenbibliothek
Unterstützt in: portierbare .NET-Plattformen
Silverlight
Verfügbar seit 4.0
Windows Phone Silverlight
Verfügbar seit 8.0
Windows Phone
Verfügbar seit 8.1
Zurück zum Anfang
Anzeigen: