diff --git a/snippets/fsharp/System/LazyT/.ctor/example.fs b/snippets/fsharp/System/LazyT/.ctor/example.fs new file mode 100644 index 00000000000..f81fb718e6b --- /dev/null +++ b/snippets/fsharp/System/LazyT/.ctor/example.fs @@ -0,0 +1,77 @@ +module example + +// +open System +open System.Threading + +type LargeObject() = + let initBy = Thread.CurrentThread.ManagedThreadId + do + printfn $"LargeObject was created on thread id {initBy}." + + member val Data = Array.zeroCreate 100000000 with get + member _.InitializedBy = initBy + +// The lazy initializer is created here. LargeObject is not created until the +// ThreadProc method executes. +// +let lazyLargeObject = Lazy() + +// The following lines show how to use other constructors to achieve exactly the +// same result as the previous line: +// let lazyLargeObject = Lazy(true) +// let lazyLargeObject = Lazy(LazyThreadSafetyMode.ExecutionAndPublication) +// + +let threadProc (state: obj) = + // Wait for the signal. + let waitForStart = state :?> ManualResetEvent + waitForStart.WaitOne() |> ignore + + // + let 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 (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, passing the same blocking event to all of them. +let startingGate = new ManualResetEvent false +let threads = [| Thread(ParameterizedThreadStart threadProc); Thread(ParameterizedThreadStart threadProc); Thread(ParameterizedThreadStart threadProc) |] +for t in threads do + t.Start startingGate + +// Give all 3 threads time to start and wait, then release them all at once. +Thread.Sleep 100 +startingGate.Set() |> ignore + +// Wait for all 3 threads to finish. (The order doesn't matter.) +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 4. +// Initialized by thread 4 last used by thread 3. +// Initialized by thread 4 last used by thread 4. +// Initialized by thread 4 last used by thread 5. +// +// Press Enter to end the program +// \ No newline at end of file diff --git a/snippets/fsharp/System/LazyT/.ctor/example1.fs b/snippets/fsharp/System/LazyT/.ctor/example1.fs new file mode 100644 index 00000000000..14293fb679b --- /dev/null +++ b/snippets/fsharp/System/LazyT/.ctor/example1.fs @@ -0,0 +1,44 @@ +module example1 + +// +open System +open System.Threading + +type LargeObject () = + do + printfn $"LargeObject was created on thread id {Thread.CurrentThread.ManagedThreadId}." + + member val Data = Array.zeroCreate 100000000 with get + +// The lazy initializer is created here. LargeObject is not created until the +// ThreadProc method executes. +// +let lazyLargeObject = Lazy false +// The following lines show how to use other constructors to achieve exactly the +// same result as the previous line: +// let lazyLargeObject = Lazy(LazyThreadSafetyMode.None) +// + +printfn """ +LargeObject is not created until you access the Value property of the lazy +initializer. Press Enter to create LargeObject.""" +stdin.ReadLine() |> ignore + +// +let large = lazyLargeObject.Value +// + +large.Data[11] <- 89 + +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 1. +// +// Press Enter to end the program +// \ No newline at end of file diff --git a/snippets/fsharp/System/LazyT/.ctor/example2.fs b/snippets/fsharp/System/LazyT/.ctor/example2.fs new file mode 100644 index 00000000000..14ae084a331 --- /dev/null +++ b/snippets/fsharp/System/LazyT/.ctor/example2.fs @@ -0,0 +1,77 @@ +module example2 + +// +open System +open System.Threading + +// +type LargeObject() = + static let mutable instanceCount = 0 + let initBy = Thread.CurrentThread.ManagedThreadId + do + if 1 = Interlocked.Increment &instanceCount then + raise (ApplicationException "Throw only ONCE.") + printfn $"LargeObject was created on thread id {initBy}." +// + member _.InitializedBy = initBy + member val Data = Array.zeroCreate 100000000 + +// +let initLargeObject () = + LargeObject() +// + +// The lazy initializer is created here. LargeObject is not created until the +// ThreadProc method executes. +// +let lazyLargeObject = Lazy initLargeObject + +// The following lines show how to use other constructors to achieve exactly the +// same result as the previous line: +// let lazyLargeObject = Lazy(initLargeObject, true) +// let lazyLargeObject = Lazy(initLargeObject, LazyThreadSafetyMode.ExecutionAndPublication) +// + +let threadProc _ = + // + try + 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]}.") + with :? ApplicationException as aex -> + printfn $"Exception: {aex.Message}" + // + +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 tries to use LargeObject. +let threads = + [| Thread(ParameterizedThreadStart threadProc); Thread(ParameterizedThreadStart threadProc); Thread(ParameterizedThreadStart threadProc) |] +for t in threads do + t.Start() + +// Wait for all 3 threads to finish. (The order doesn't matter.) +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. +// +// Exception: Throw only ONCE. +// Exception: Throw only ONCE. +// Exception: Throw only ONCE. +// +// Press Enter to end the program +// \ No newline at end of file diff --git a/snippets/fsharp/System/LazyT/.ctor/example3.fs b/snippets/fsharp/System/LazyT/.ctor/example3.fs new file mode 100644 index 00000000000..4d62f973246 --- /dev/null +++ b/snippets/fsharp/System/LazyT/.ctor/example3.fs @@ -0,0 +1,59 @@ +module example3 + +// +open System +open System.Threading + +// +type LargeObject() = + static let mutable pleaseThrow = true + do + if pleaseThrow then + pleaseThrow <- false + raise (ApplicationException "Throw only ONCE.") + printfn $"LargeObject was created on thread id {Thread.CurrentThread.ManagedThreadId}." +// + member val Data = Array.zeroCreate 100000000 + +// +let initLargeObject () = + LargeObject() +// + +// The lazy initializer is created here. LargeObject is not created until the +// ThreadProc method executes. +// +let lazyLargeObject = Lazy(initLargeObject, false) + +// The following lines show how to use other constructors to achieve exactly the +// same result as the previous line: +// let lazyLargeObject = Lazy(initLargeObject, LazyThreadSafetyMode.None) +// + +printfn """ +LargeObject is not created until you access the Value property of the lazy +initializer. Press Enter to create LargeObject (three tries).""" +stdin.ReadLine() |> ignore + +// +for _ = 0 to 2 do + try + let large = lazyLargeObject.Value + large.Data[11] <- 89 + with :? ApplicationException as aex -> + printfn $"Exception: {aex.Message}" +// + +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 (three tries). +// +// Exception: Throw only ONCE. +// Exception: Throw only ONCE. +// Exception: Throw only ONCE. +// +// Press Enter to end the program +// \ No newline at end of file diff --git a/snippets/fsharp/System/LazyT/.ctor/example4.fs b/snippets/fsharp/System/LazyT/.ctor/example4.fs new file mode 100644 index 00000000000..43bea19acad --- /dev/null +++ b/snippets/fsharp/System/LazyT/.ctor/example4.fs @@ -0,0 +1,93 @@ +// +open System +open System.Threading + +// +type LargeObject(initBy) = + do + printfn $"Constructor: Instance initializing on thread {initBy}" + + override _.Finalize() = + printfn $"Finalizer: Instance was initialized on {initBy}" +// + member _.InitializedBy = initBy + member val Data = Array.zeroCreate 100000000 with get + +// Factory function for lazy initialization. +// +let mutable instanceCount = 0 +let initLargeObject () = + if 1 = Interlocked.Increment &instanceCount then + raise (ApplicationException $"Lazy initialization function failed on thread {Thread.CurrentThread.ManagedThreadId}.") + LargeObject Thread.CurrentThread.ManagedThreadId +// + +// The lazy initializer is created here. LargeObject is not created until the +// ThreadProc method executes. +// +let lazyLargeObject = Lazy(initLargeObject, LazyThreadSafetyMode.PublicationOnly) +// + +let threadProc (state: obj) = + // Wait for the signal. + let waitForStart = state :?> ManualResetEvent + waitForStart.WaitOne() |> ignore + + // + try + let 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 (fun () -> + large.Data[0] <- Thread.CurrentThread.ManagedThreadId + printfn $"LargeObject was initialized by thread {large.InitializedBy} last used by thread {large.Data[0]}.") + with :? ApplicationException as ex -> + printfn $"ApplicationException: {ex.Message}" + // + +// Create and start 3 threads, passing the same blocking event to all of them. +let startingGate = new ManualResetEvent false +let threads = + [| Thread(ParameterizedThreadStart threadProc); Thread(ParameterizedThreadStart threadProc); Thread(ParameterizedThreadStart threadProc) |] +for t in threads do + t.Start startingGate + +// Give all 3 threads time to start and wait, then release them all at once. +Thread.Sleep 50 +startingGate.Set() |> ignore + +// Wait for all 3 threads to finish. (The order doesn't matter.) +for t in threads do + t.Join() + +printfn "\nThreads are complete. Running GC.Collect() to reclaim extra instances." + +GC.Collect() + +// Allow time for garbage collection, which happens asynchronously. +Thread.Sleep 100 + +printfn "\nNote that only one instance of LargeObject was used." +printfn "Press Enter to end the program" +stdin.ReadLine() |> ignore + +// 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 +// \ No newline at end of file diff --git a/snippets/fsharp/System/LazyT/.ctor/example5.fs b/snippets/fsharp/System/LazyT/.ctor/example5.fs new file mode 100644 index 00000000000..e4ce78ddd40 --- /dev/null +++ b/snippets/fsharp/System/LazyT/.ctor/example5.fs @@ -0,0 +1,89 @@ +module example5 + +// +open System +open System.Threading + +// +type LargeObject() = + let initBy = Thread.CurrentThread.ManagedThreadId + do + printfn $"Constructor: Instance initializing on thread {initBy}" + + override _.Finalize() = + printfn $"Finalizer: Instance was initialized on {initBy}" +// + + member _.InitializedBy = initBy + member val Data = Array.zeroCreate 100000000 + +// The lazy initializer is created here. LargeObject is not created until the +// ThreadProc method executes. +// +let lazyLargeObject = Lazy LazyThreadSafetyMode.PublicationOnly +// + +let threadProc (state: obj) = + // Wait for the signal. + let waitForStart = state :?> ManualResetEvent + waitForStart.WaitOne() |> ignore + + // + let 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 (fun () -> + large.Data[0] <- Thread.CurrentThread.ManagedThreadId + printfn $"LargeObject was initialized by thread {large.InitializedBy} last used by thread {large.Data[0]}.") + +// Create and start 3 threads, passing the same blocking event to all of them. +let startingGate = new ManualResetEvent false +let threads = + [| Thread(ParameterizedThreadStart threadProc); Thread(ParameterizedThreadStart threadProc); Thread(ParameterizedThreadStart threadProc) |] +for t in threads do + t.Start startingGate + +// Give all 3 threads time to start and wait, then release them all at once. +Thread.Sleep 50 +startingGate.Set() |> ignore + +// Wait for all 3 threads to finish. (The order doesn't matter.) +for t in threads do + t.Join() + +printfn "\nThreads are complete. Running GC.Collect() to reclaim the extra instances." + +GC.Collect() + +// Allow time for garbage collection, which happens asynchronously. +Thread.Sleep 100 + +printfn "\nNote that all three threads used the instance that was not collected." +printfn "Press Enter to end the program" +stdin.ReadLine() |> ignore + + +// This example produces output similar to the following: +// Constructor: Instance initializing on thread 4 +// Constructor: Instance initializing on thread 3 +// Constructor: Instance initializing on thread 5 +// LargeObject was initialized by thread 4 last used by thread 4. +// LargeObject was initialized by thread 4 last used by thread 5. +// LargeObject was initialized by thread 4 last used by thread 3. +// +// Threads are complete. Running GC.Collect() to reclaim the extra instances. +// Finalizer: Instance was initialized on 3 +// Finalizer: Instance was initialized on 5 +// +// Note that all three threads used the instance that was not collected. +// Press Enter to end the program +// +// Instance finalizing initialized on 4 +// \ No newline at end of file diff --git a/snippets/fsharp/System/LazyT/.ctor/fs.fsproj b/snippets/fsharp/System/LazyT/.ctor/fs.fsproj new file mode 100644 index 00000000000..90db281f7ae --- /dev/null +++ b/snippets/fsharp/System/LazyT/.ctor/fs.fsproj @@ -0,0 +1,15 @@ + + + Exe + net6.0 + + + + + + + + + + + \ No newline at end of file diff --git a/snippets/fsharp/System/LazyT/Overview/example.fs b/snippets/fsharp/System/LazyT/Overview/example.fs new file mode 100644 index 00000000000..182a043611b --- /dev/null +++ b/snippets/fsharp/System/LazyT/Overview/example.fs @@ -0,0 +1,75 @@ +module example + +// +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 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 initLargeObject + +// The following lines show how to use other constructors to achieve exactly the +// same result as the previous line: +// let lazyLargeObject = Lazy(initLargeObject, true) +// let lazyLargeObject = Lazy(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 +// \ No newline at end of file diff --git a/snippets/fsharp/System/LazyT/Overview/fs.fsproj b/snippets/fsharp/System/LazyT/Overview/fs.fsproj new file mode 100644 index 00000000000..20123b1269f --- /dev/null +++ b/snippets/fsharp/System/LazyT/Overview/fs.fsproj @@ -0,0 +1,11 @@ + + + Exe + net6.0 + + + + + + + \ No newline at end of file diff --git a/snippets/fsharp/System/LazyT/Overview/lambda.fs b/snippets/fsharp/System/LazyT/Overview/lambda.fs new file mode 100644 index 00000000000..ca5453e4825 --- /dev/null +++ b/snippets/fsharp/System/LazyT/Overview/lambda.fs @@ -0,0 +1,46 @@ +module lambda + +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 100000000 + +// +let lazyLargeObject = Lazy(fun () -> + let large = LargeObject Thread.CurrentThread.ManagedThreadId + // Perform additional initialization here. + large) +// + +let threadProc _ = + 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 \ No newline at end of file diff --git a/xml/System/Lazy`1.xml b/xml/System/Lazy`1.xml index eb56ea7a600..0afde151003 100644 --- a/xml/System/Lazy`1.xml +++ b/xml/System/Lazy`1.xml @@ -130,32 +130,38 @@ The example defines a `LargeObject` class that will be initialized lazily by one of several threads. The four key sections of code illustrate the creation of the initializer, the factory method, the actual initialization, and the constructor of the `LargeObject` class, which displays a message when the object is created. At the beginning of the `Main` method, the example creates the thread-safe lazy initializer for `LargeObject`: :::code language="csharp" source="~/snippets/csharp/System/LazyT/Overview/example.cs" id="Snippetnewlazy"::: + :::code language="fsharp" source="~/snippets/fsharp/System/LazyT/Overview/example.fs" id="Snippetnewlazy"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.lazy`1/vb/example.vb" id="Snippetnewlazy"::: The factory method shows the creation of the object, with a placeholder for further initialization: :::code language="csharp" source="~/snippets/csharp/System/LazyT/Overview/example.cs" id="Snippetfactoryfunc"::: + :::code language="fsharp" source="~/snippets/fsharp/System/LazyT/Overview/example.fs" id="Snippetfactoryfunc"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.lazy`1/vb/example.vb" id="Snippetfactoryfunc"::: Note that the first two code sections could be combined by using a lambda function, as shown here: :::code language="csharp" source="~/snippets/csharp/System/LazyT/Overview/lambda.cs" id="Snippetinitwithlambda"::: + :::code language="fsharp" source="~/snippets/fsharp/System/LazyT/Overview/lambda.fs" id="Snippetinitwithlambda"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.lazy`1/vb/lambda.vb" id="Snippetinitwithlambda"::: The example pauses, to indicate that an indeterminate period may elapse before lazy initialization occurs. When you press the **Enter** key, the example creates and starts three threads. The `ThreadProc` method that's used by all three threads calls the property. The first time this happens, the `LargeObject` instance is created: :::code language="csharp" source="~/snippets/csharp/System/LazyT/Overview/example.cs" id="Snippetvalueprop"::: + :::code language="fsharp" source="~/snippets/fsharp/System/LazyT/Overview/example.fs" id="Snippetvalueprop"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.lazy`1/vb/example.vb" id="Snippetvalueprop"::: The constructor of the `LargeObject` class, which includes the last key section of code, displays a message and records the identity of the initializing thread. The output from the program appears at the end of the full code listing. :::code language="csharp" source="~/snippets/csharp/System/LazyT/Overview/example.cs" id="Snippetlargector"::: + :::code language="fsharp" source="~/snippets/fsharp/System/LazyT/Overview/example.fs" id="Snippetlargector"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.lazy`1/vb/example.vb" id="Snippetlargector"::: > [!NOTE] > For simplicity, this example uses a global instance of , and all the methods are `static` (`Shared` in Visual Basic). These are not requirements for the use of lazy initialization. :::code language="csharp" source="~/snippets/csharp/System/LazyT/Overview/example.cs" id="Snippetall"::: + :::code language="fsharp" source="~/snippets/fsharp/System/LazyT/Overview/example.fs" id="Snippetall"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.lazy`1/vb/example.vb" id="Snippetall"::: ]]> @@ -163,6 +169,7 @@ By default, all public and protected members of the class are thread safe and may be used concurrently from multiple threads. These thread-safety guarantees may be removed optionally and per instance, using parameters to the type's constructors. Lazy Initialization + Lazy Expressions (F#) @@ -231,11 +238,13 @@ The example defines a `LargeObject` class that will be initialized lazily by one of several threads. The two key lines of code in this example are the creation of the initializer and the actual initialization. At the beginning of the `Main` method, the example creates the thread-safe lazy initializer for `LargeObject`: :::code language="csharp" source="~/snippets/csharp/System/LazyT/.ctor/example.cs" id="Snippetnewlazy"::: + :::code language="fsharp" source="~/snippets/fsharp/System/LazyT/.ctor/example.fs" id="Snippetnewlazy"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.lazy`1.ctor/vb/example.vb" id="Snippetnewlazy"::: The example creates and starts three threads that block on a object, so that the example can release the threads all at once. The `ThreadProc` method that's used by all three threads calls the property to get the `LargeObject` instance: :::code language="csharp" source="~/snippets/csharp/System/LazyT/.ctor/example.cs" id="Snippetvalueprop"::: + :::code language="fsharp" source="~/snippets/fsharp/System/LazyT/.ctor/example.fs" id="Snippetvalueprop"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.lazy`1.ctor/vb/example.vb" id="Snippetvalueprop"::: The class provides locking, so that only one thread is allowed to create the `LargeObject` instance. The example demonstrates that the other threads all get the same instance. @@ -244,6 +253,7 @@ > For simplicity, this example uses a global instance of , and all the methods are `static` (`Shared` in Visual Basic). These are not requirements for the use of lazy initialization. :::code language="csharp" source="~/snippets/csharp/System/LazyT/.ctor/example.cs" id="Snippetall"::: + :::code language="fsharp" source="~/snippets/fsharp/System/LazyT/.ctor/example.fs" id="Snippetall"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.lazy`1.ctor/vb/example.vb" id="Snippetall"::: ]]> @@ -313,6 +323,7 @@ > For simplicity, this example uses a global instance of , and all the methods are `static` (`Shared` in Visual Basic). These are not requirements for the use of lazy initialization. :::code language="csharp" source="~/snippets/csharp/System/LazyT/.ctor/example1.cs" id="Snippetall"::: + :::code language="fsharp" source="~/snippets/fsharp/System/LazyT/.ctor/example1.fs" id="Snippetall"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.lazy`1.ctorbool/vb/example.vb" id="Snippetall"::: ]]> @@ -377,16 +388,19 @@ The example defines a `LargeObject` class that will be initialized lazily by one of several threads. The three key sections of code illustrate the creation of the initializer, the actual initialization, and the constructor of the `LargeObject` class, which demonstrates exception caching. At the beginning of the `Main` method, the example creates the thread-safe lazy initializer for `LargeObject`: :::code language="csharp" source="~/snippets/csharp/System/LazyT/.ctor/example2.cs" id="Snippetnewlazy"::: + :::code language="fsharp" source="~/snippets/fsharp/System/LazyT/.ctor/example2.fs" id="Snippetnewlazy"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.lazy`1.ctorfunc/vb/example.vb" id="Snippetnewlazy"::: The example creates and starts three threads. The `ThreadProc` method that's used by all three threads calls the property to get the `LargeObject` instance: :::code language="csharp" source="~/snippets/csharp/System/LazyT/.ctor/example2.cs" id="Snippetvalueprop"::: + :::code language="fsharp" source="~/snippets/fsharp/System/LazyT/.ctor/example2.fs" id="Snippetvalueprop"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.lazy`1.ctorfunc/vb/example.vb" id="Snippetvalueprop"::: In the constructor of the `LargeObject` class, the third key section of code throws an exception the first time a `LargeObject` instance is created, but thereafter allows instance creation to occur: :::code language="csharp" source="~/snippets/csharp/System/LazyT/.ctor/example2.cs" id="Snippetlargector"::: + :::code language="fsharp" source="~/snippets/fsharp/System/LazyT/.ctor/example2.fs" id="Snippetlargector"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.lazy`1.ctorfunc/vb/example.vb" id="Snippetlargector"::: When the example is run, the first thread that tries to create an instance of `LargeObject` fails, and the exception is caught. You might expect that the next thread would successfully create an instance, but the object has cached the exception. Because of this, all three threads throw the exception. @@ -395,6 +409,7 @@ > For simplicity, this example uses a global instance of , and all the methods are `static` (`Shared` in Visual Basic). These are not requirements for the use of lazy initialization. :::code language="csharp" source="~/snippets/csharp/System/LazyT/.ctor/example2.cs" id="Snippetall"::: + :::code language="fsharp" source="~/snippets/fsharp/System/LazyT/.ctor/example2.fs" id="Snippetall"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.lazy`1.ctorfunc/vb/example.vb" id="Snippetall"::: ]]> @@ -462,16 +477,19 @@ The example defines a `LargeObject` class that will be initialized lazily by any of several threads. The three key sections of code illustrate the creation of the initializer, the actual initialization, and the constructor and finalizer of the `LargeObject` class. At the beginning of the `Main` method, the example creates the object that performs lazy initialization of the `LargeObject`: :::code language="csharp" source="~/snippets/csharp/System/LazyT/.ctor/example5.cs" id="Snippetnewlazy"::: + :::code language="fsharp" source="~/snippets/fsharp/System/LazyT/.ctor/example5.fs" id="Snippetnewlazy"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.lazy`1.ctorltsm/vb/example.vb" id="Snippetnewlazy"::: The example creates and starts three threads that block on a object, so that the example can release the threads all at once. In the `ThreadProc` method that's used by all three threads, calling the property creates the `LargeObject` instance: :::code language="csharp" source="~/snippets/csharp/System/LazyT/.ctor/example5.cs" id="Snippetvalueprop"::: + :::code language="fsharp" source="~/snippets/fsharp/System/LazyT/.ctor/example5.fs" id="Snippetvalueprop"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.lazy`1.ctorltsm/vb/example.vb" id="Snippetvalueprop"::: Because the constructor for the instance specified , all three threads are allowed to create `LargeObject` instances. The example demonstrates this by displaying console messages in the constructor and in the finalizer of the `LargeObject` class: :::code language="csharp" source="~/snippets/csharp/System/LazyT/.ctor/example5.cs" id="Snippetctorfinalizer"::: + :::code language="fsharp" source="~/snippets/fsharp/System/LazyT/.ctor/example5.fs" id="Snippetctorfinalizer"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.lazy`1.ctorltsm/vb/example.vb" id="Snippetctorfinalizer"::: However, the object ensures that only one instance is used by all threads. The output from the example shows that all three threads use the same instance, and also shows that the other two instances can be reclaimed by garbage collection. @@ -480,6 +498,7 @@ > For simplicity, this example uses a global instance of , and all the methods are `static` (`Shared` in Visual Basic). These are not requirements for the use of lazy initialization. :::code language="csharp" source="~/snippets/csharp/System/LazyT/.ctor/example5.cs" id="Snippetall"::: + :::code language="fsharp" source="~/snippets/fsharp/System/LazyT/.ctor/example5.fs" id="Snippetall"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.lazy`1.ctorltsm/vb/example.vb" id="Snippetall"::: ]]> @@ -593,16 +612,19 @@ An instance created with this constructor is usable by multiple threads concurre The example defines a `LargeObject` class that will be initialized lazily by one of several threads. The three key sections of code illustrate the creation of the initializer, the actual initialization, and the constructor of the `LargeObject` class, which demonstrates exception caching. At the beginning of the `Main` method, the example creates the thread-safe lazy initializer for `LargeObject`: :::code language="csharp" source="~/snippets/csharp/System/LazyT/.ctor/example3.cs" id="Snippetnewlazy"::: + :::code language="fsharp" source="~/snippets/fsharp/System/LazyT/.ctor/example3.fs" id="Snippetnewlazy"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.lazy`1.ctorfuncbool/vb/example.vb" id="Snippetnewlazy"::: In the call to the constructor, the `isThreadSafe` parameter is `false`, so the is not thread safe. Because it's not thread safe, the example calls the property three times on the same thread: :::code language="csharp" source="~/snippets/csharp/System/LazyT/.ctor/example3.cs" id="Snippetvalueprop"::: + :::code language="fsharp" source="~/snippets/fsharp/System/LazyT/.ctor/example3.fs" id="Snippetvalueprop"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.lazy`1.ctorfuncbool/vb/example.vb" id="Snippetvalueprop"::: In the constructor of the `LargeObject` class, the third key section of code throws an exception the first time a `LargeObject` instance is created, but thereafter allows instance creation to occur: :::code language="csharp" source="~/snippets/csharp/System/LazyT/.ctor/example3.cs" id="Snippetlargector"::: + :::code language="fsharp" source="~/snippets/fsharp/System/LazyT/.ctor/example3.fs" id="Snippetlargector"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.lazy`1.ctorfuncbool/vb/example.vb" id="Snippetlargector"::: When the example is run, the first attempt to create an instance of `LargeObject` fails, and the exception is caught. You might expect that the next attempt would succeed, but the object has cached the exception. Because of this, all three attempts throw the exception. @@ -611,6 +633,7 @@ An instance created with this constructor is usable by multiple threads concurre > For simplicity, this example uses a global instance of , and all the methods are `static` (`Shared` in Visual Basic). These are not requirements for the use of lazy initialization. :::code language="csharp" source="~/snippets/csharp/System/LazyT/.ctor/example3.cs" id="Snippetall"::: + :::code language="fsharp" source="~/snippets/fsharp/System/LazyT/.ctor/example3.fs" id="Snippetall"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.lazy`1.ctorfuncbool/vb/example.vb" id="Snippetall"::: ]]> @@ -680,6 +703,7 @@ An instance created with this constructor is usable by multiple threads concurre The example defines a `LargeObject` class that will be initialized lazily by any of several threads. The four key sections of code illustrate the creation of the initializer, the actual initialization, the initialization function, and the constructor and finalizer of the `LargeObject` class. At the beginning of the `Main` method, the example creates the object that performs lazy initialization of the `LargeObject`: :::code language="csharp" source="~/snippets/csharp/System/LazyT/.ctor/example4.cs" id="Snippetnewlazy"::: + :::code language="fsharp" source="~/snippets/fsharp/System/LazyT/.ctor/example4.fs" id="Snippetnewlazy"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.lazy`1.ctorfuncltsm/vb/example.vb" id="Snippetnewlazy"::: The lazy initializer uses a function to perform the initialization. In this case, a function is required because there is no parameterless constructor for the `LargeObject` class. @@ -687,11 +711,13 @@ An instance created with this constructor is usable by multiple threads concurre The example creates and starts three threads that block on a object, so that the example can release the threads all at once. In the `ThreadProc` method that's used by all three threads, calling the property creates the `LargeObject` instance: :::code language="csharp" source="~/snippets/csharp/System/LazyT/.ctor/example4.cs" id="Snippetvalueprop"::: + :::code language="fsharp" source="~/snippets/fsharp/System/LazyT/.ctor/example4.fs" id="Snippetvalueprop"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.lazy`1.ctorfuncltsm/vb/example.vb" id="Snippetvalueprop"::: In the third key section of code, the lazy initialization function is called to create the `LargeObject` instance. The function throws an exception the first time it's called: :::code language="csharp" source="~/snippets/csharp/System/LazyT/.ctor/example4.cs" id="Snippetfactoryfunc"::: + :::code language="fsharp" source="~/snippets/fsharp/System/LazyT/.ctor/example4.fs" id="Snippetfactoryfunc"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.lazy`1.ctorfuncltsm/vb/example.vb" id="Snippetfactoryfunc"::: With any other setting, an unhandled exception in the initialization function would be cached. However, suppresses exception caching. The output from the example demonstrates that a subsequent attempt to initialize the object succeeds. @@ -702,6 +728,7 @@ An instance created with this constructor is usable by multiple threads concurre Because the constructor for the instance specified , all three threads are allowed to create `LargeObject` instances. The example demonstrates this by displaying console messages in the constructor and in the finalizer of the `LargeObject` class: :::code language="csharp" source="~/snippets/csharp/System/LazyT/.ctor/example4.cs" id="Snippetctorfinalizer"::: + :::code language="fsharp" source="~/snippets/fsharp/System/LazyT/.ctor/example4.fs" id="Snippetctorfinalizer"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.lazy`1.ctorfuncltsm/vb/example.vb" id="Snippetctorfinalizer"::: The object ensures that only one instance is used by all threads (except the thread where the initialization function throws an exception). The output from the example shows this. @@ -710,6 +737,7 @@ An instance created with this constructor is usable by multiple threads concurre > For simplicity, this example uses a global instance of , and all the methods are `static` (`Shared` in Visual Basic). These are not requirements for the use of lazy initialization. :::code language="csharp" source="~/snippets/csharp/System/LazyT/.ctor/example4.cs" id="Snippetall"::: + :::code language="fsharp" source="~/snippets/fsharp/System/LazyT/.ctor/example4.fs" id="Snippetall"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.lazy`1.ctorfuncltsm/vb/example.vb" id="Snippetall"::: ]]>