Questo articolo è stato tradotto automaticamente. Per visualizzare l'articolo in inglese, selezionare la casella di controllo Inglese. È possibile anche visualizzare il testo inglese in una finestra popup posizionando il puntatore del mouse sopra il testo.
Traduzione
Inglese

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

 

Data di pubblicazione: ottobre 2016

Inizializza una nuova istanza della classe Lazy<T> che usa la funzione di inizializzazione e la modalità thread safety specificate.

Spazio dei nomi:   System
Assembly:  mscorlib (in mscorlib.dll)

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

Parametri

valueFactory
Type: System.Func<T>

Delegato richiamato per produrre il valore inizializzato in modalità differita quando è necessario.

mode
Type: System.Threading.LazyThreadSafetyMode

Uno dei valori di enumerazione che specifica la modalità thread safety.

Exception Condition
ArgumentOutOfRangeException

mode contiene un valore non valido.

ArgumentNullException

valueFactory è null.

La modalità thread safety di un Lazy<T> istanza viene descritto il comportamento quando più thread tentano di inizializzare il Lazy<T> istanza.

Le eccezioni generate da valueFactory vengono memorizzati nella cache, a meno che non mode è PublicationOnly. Per ulteriori informazioni, vedere la classe Lazy<T> o l'enumerazione System.Threading.LazyThreadSafetyMode.

Nell'esempio seguente viene illustrato l'utilizzo di questo costruttore per creare un inizializzatore lazy che consente a più thread per situazioni di race per creare un oggetto in modo differito. Più thread riesca nella creazione di istanze, ma l'istanza è stata creata prima di utilizzare tutti i thread. Inoltre, nell'esempio viene illustrato che le eccezioni non vengono mai memorizzati nella cache quando si specifica PublicationOnly, anche se l'inizializzazione viene eseguita da una funzione anziché dal costruttore predefinito del tipo creato in modo differito.

System_CAPS_noteNota

Per un esempio che illustra come utilizzare questo costruttore in scenari a thread singolo (specificando LazyThreadSafetyMode.None per mode), vedere il Lazy<T>(Boolean) costruttore. Per un esempio che illustra come utilizzare questo costruttore per fornire il blocco anziché race condition in scenari con multithreading (specificando LazyThreadSafetyMode.ExecutionAndPublication per mode), vedere il Lazy<T>() costruttore.

Nell'esempio viene definito un LargeObject classe che verrà inizializzata in modo differito da uno dei diversi thread. Le quattro sezioni principali del codice vengono illustrate la creazione di inizializzatore di, l'effettiva inizializzazione, la funzione di inizializzazione e il costruttore e il finalizzatore della LargeObject classe. All'inizio del Main (metodo), nell'esempio viene creata la Lazy<T> oggetto che esegue l'inizializzazione differita del LargeObject:

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

L'inizializzatore lazy utilizza una funzione per eseguire l'inizializzazione. In questo caso, una funzione è necessario perché è presente alcun costruttore predefinito per il LargeObject classe.

L'esempio crea e avvia tre thread che bloccano su un ManualResetEvent dell'oggetto, in modo che l'esempio è possibile rilasciare i thread in una sola volta. Nel ThreadProc metodo utilizzato da tutti i thread, la chiamata di Value proprietà crea la LargeObject istanza:

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

Nella terza sezione chiave del codice, viene chiamata la funzione di inizializzazione differita per creare il LargeObject istanza. La funzione genera un'ora di eccezione, il primo che viene chiamato:

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

Con qualsiasi altro LazyThreadSafetyMode impostazione, un'eccezione non gestita nella funzione di inizializzazione potrebbe essere memorizzato nella cache. Tuttavia, PublicationOnly evita la memorizzazione nella cache di eccezione. L'output dell'esempio viene illustrato che un successivo tentativo di inizializzare l'oggetto ha esito positivo.

System_CAPS_noteNota

In genere viene visualizzato il messaggio di eccezione dopo i messaggi che indicano che altri thread è inizializzati correttamente l'oggetto. Equivale a causa del ritardo introdotto da generare e intercettare l'eccezione.

Poiché il costruttore per il Lazy<T> istanza specificata LazyThreadSafetyMode.PublicationOnly, tutti i thread sono autorizzati a creare LargeObject istanze. Nell'esempio viene illustrato questo visualizzando i messaggi della console nel costruttore e nel finalizzatore del LargeObject classe:

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

Il Lazy<T> oggetto garantisce che solo un'istanza viene utilizzata da tutti i thread (eccetto il thread in cui la funzione di inizializzazione genera un'eccezione). L'output di esempio illustrata questa operazione.

System_CAPS_noteNota

Per semplicità, in questo esempio viene utilizzata un'istanza globale di Lazy<T> e tutti i metodi sono static (Shared in Visual Basic). Questi non sono requisiti per l'uso di inizializzazione differita.

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

Universal Windows Platform
Disponibile da 8
.NET Framework
Disponibile da 4.0
Libreria di classi portabile
Supportato in: piattaforme .NET portabili
Silverlight
Disponibile da 4.0
Windows Phone Silverlight
Disponibile da 8.0
Windows Phone
Disponibile da 8.1
Torna all'inizio
Mostra: