diff --git a/Lazy/Lazy.sln b/Lazy/Lazy.sln
new file mode 100644
index 0000000..ccbe521
--- /dev/null
+++ b/Lazy/Lazy.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.4.33403.182
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lazy", "Lazy\Lazy.csproj", "{F8C3CCDA-224A-4684-8E2E-B649BDBB08D3}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestsForLazy", "TestsForLazy\TestsForLazy.csproj", "{A08651D9-B95A-4E33-A8B0-D5635E0523C8}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {F8C3CCDA-224A-4684-8E2E-B649BDBB08D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F8C3CCDA-224A-4684-8E2E-B649BDBB08D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F8C3CCDA-224A-4684-8E2E-B649BDBB08D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F8C3CCDA-224A-4684-8E2E-B649BDBB08D3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A08651D9-B95A-4E33-A8B0-D5635E0523C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A08651D9-B95A-4E33-A8B0-D5635E0523C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A08651D9-B95A-4E33-A8B0-D5635E0523C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A08651D9-B95A-4E33-A8B0-D5635E0523C8}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {8BB48519-EA16-4F07-8949-4E4CC34A90F4}
+ EndGlobalSection
+EndGlobal
diff --git a/Lazy/Lazy/ILazy.cs b/Lazy/Lazy/ILazy.cs
new file mode 100644
index 0000000..29aaacb
--- /dev/null
+++ b/Lazy/Lazy/ILazy.cs
@@ -0,0 +1,12 @@
+namespace Lazy;
+
+///
+/// The class implements an object whose function is called only once.
+///
+public interface ILazy
+{
+ ///
+ /// Gets the created object.
+ ///
+ T? Get();
+}
\ No newline at end of file
diff --git a/Lazy/Lazy/Lazy.csproj b/Lazy/Lazy/Lazy.csproj
new file mode 100644
index 0000000..424caff
--- /dev/null
+++ b/Lazy/Lazy/Lazy.csproj
@@ -0,0 +1,11 @@
+
+
+
+ Exe
+ net7.0
+ enable
+ enable
+ Library
+
+
+
diff --git a/Lazy/Lazy/MultiThreadLazy.cs b/Lazy/Lazy/MultiThreadLazy.cs
new file mode 100644
index 0000000..9bca5ea
--- /dev/null
+++ b/Lazy/Lazy/MultiThreadLazy.cs
@@ -0,0 +1,57 @@
+namespace Lazy;
+
+public class MultiThreadLazy : ILazy
+{
+ private Func? supplier;
+ private readonly Object objectLock = new ();
+ private volatile bool isCalculated = false;
+ private T? resultSuppiler;
+ private Exception? exceptionSuppiler = default;
+
+ ///
+ /// Constructor for storing the object creation function
+ ///
+ public MultiThreadLazy(Func function)
+ {
+ supplier = function;
+ }
+
+ public T? Get()
+ {
+ if (!isCalculated)
+ {
+ lock (objectLock)
+ {
+ if (!isCalculated)
+ {
+ try
+ {
+ if (supplier == null)
+ {
+ resultSuppiler = default;
+ }
+ else
+ {
+ resultSuppiler = supplier();
+ }
+ }
+ catch (Exception ex)
+ {
+ exceptionSuppiler = ex;
+ }
+ finally
+ {
+ supplier = null;
+ }
+ isCalculated = true;
+ }
+ }
+ }
+
+ if (exceptionSuppiler != default)
+ {
+ throw exceptionSuppiler;
+ }
+ return resultSuppiler;
+ }
+}
\ No newline at end of file
diff --git a/Lazy/Lazy/SingleThreadLazy.cs b/Lazy/Lazy/SingleThreadLazy.cs
new file mode 100644
index 0000000..e4f9747
--- /dev/null
+++ b/Lazy/Lazy/SingleThreadLazy.cs
@@ -0,0 +1,45 @@
+namespace Lazy;
+
+public class SingleThreadLazy : ILazy
+{
+ private Func? supplier;
+ private bool isCalculated = false;
+ private T? resultSuppiler;
+ private Exception? exceptionFromSuppiler = default;
+
+ ///
+ /// Constructor for storing the object creation function
+ ///
+ public SingleThreadLazy(Func function)
+ {
+ supplier = function;
+ }
+
+ public T? Get()
+ {
+ if (!isCalculated)
+ {
+ try
+ {
+ if (supplier != null)
+ {
+ resultSuppiler = supplier();
+ }
+ }
+ catch (Exception ex)
+ {
+ exceptionFromSuppiler = ex;
+ }
+ finally
+ {
+ supplier = null;
+ }
+ isCalculated = true;
+ }
+ if (exceptionFromSuppiler != default)
+ {
+ throw exceptionFromSuppiler;
+ }
+ return resultSuppiler;
+ }
+}
\ No newline at end of file
diff --git a/Lazy/TestsForLazy/FunctionsForTests.cs b/Lazy/TestsForLazy/FunctionsForTests.cs
new file mode 100644
index 0000000..86afc36
--- /dev/null
+++ b/Lazy/TestsForLazy/FunctionsForTests.cs
@@ -0,0 +1,28 @@
+namespace Lazy;
+
+///
+/// Class implements functions for checking Lazy
+///
+public class FunctionsForTests
+{
+ private int howMuchFunctionBeenCalled = 0;
+
+ ///
+ /// Function that counts how much it is caused by
+ ///
+ public int FunctionForLazyWithCounter()
+ {
+ Interlocked.Increment(ref howMuchFunctionBeenCalled);
+ return howMuchFunctionBeenCalled;
+ }
+
+ ///
+ /// Function that throws DivideByZeroException
+ ///
+ ///
+ public int DivideByZeroException()
+ {
+ var firstNumber = 1;
+ return firstNumber / 0;
+ }
+}
\ No newline at end of file
diff --git a/Lazy/TestsForLazy/TestsForLazy.cs b/Lazy/TestsForLazy/TestsForLazy.cs
new file mode 100644
index 0000000..6ffc03e
--- /dev/null
+++ b/Lazy/TestsForLazy/TestsForLazy.cs
@@ -0,0 +1,113 @@
+namespace TestsForLazy;
+using Lazy;
+
+public class Tests
+{
+ private static readonly FunctionsForTests globalFunctionsForTestsForSingleThread = new();
+ private static readonly FunctionsForTests globalFunctionsForTestsForMultiThread = new();
+
+ [Test]
+ public void SimpleExampleWithMultiThreadLazy()
+ {
+ var functionsForTests = new FunctionsForTests();
+ var multiThreadLazy = new MultiThreadLazy(() => functionsForTests.FunctionForLazyWithCounter());
+ var arrayThreads = new Thread[10];
+
+ var arrayResult = new int[10];
+
+ for (int i = 0; i < arrayThreads.Length; i++)
+ {
+ var local = i;
+ arrayThreads[i] = new Thread(() =>
+ {
+ for (var j = local; j < 10; j++)
+ {
+ arrayResult[j] = multiThreadLazy.Get();
+ }
+ });
+ }
+
+ foreach (var thread in arrayThreads)
+ {
+ thread.Start();
+ }
+
+ foreach (var element in arrayThreads)
+ {
+ element.Join();
+ }
+
+ foreach (var element in arrayResult)
+ {
+ Assert.That(element, Is.EqualTo(1));
+ }
+ }
+
+ [TestCaseSource(nameof(LazyForTestWithFunctionWithCounter))]
+ public void SimpleExampleWithOneThread(ILazy lazy)
+ {
+ for (int i = 0; i < 10; ++i)
+ {
+ Assert.That(lazy.Get(), Is.EqualTo(1));
+ }
+ }
+
+ [TestCaseSource(nameof(LazyForTestWithFunctionWithException))]
+ public void ExampleWithExceptionWithOneThread(ILazy lazy)
+ {
+ for (int i = 0; i < 10; ++i)
+ {
+ Assert.Throws(() => lazy.Get());
+ }
+ }
+
+ [Test]
+ public void ThreadRaceTest()
+ {
+ var functionsForTests = new FunctionsForTests();
+ var multiThreadLazy = new MultiThreadLazy(() => functionsForTests.FunctionForLazyWithCounter());
+ var arrayThreads = new Thread[10];
+ var arrayResult = new int[10];
+
+ for (int i = 0; i < arrayThreads.Length; i++)
+ {
+ var local = i;
+ arrayThreads[i] = new Thread(() =>
+ {
+ for (var j = local; j < 10; j++)
+ {
+ arrayResult[j] = multiThreadLazy.Get();
+ }
+ });
+ }
+
+ foreach (var element in arrayThreads)
+ {
+ element.Start();
+ }
+
+ foreach (var element in arrayThreads)
+ {
+ element.Join();
+ }
+
+ foreach (var element in arrayResult)
+ {
+ Assert.That(element, Is.EqualTo(1));
+ }
+ }
+
+ private static IEnumerable LazyForTestWithFunctionWithCounter
+ => new TestCaseData[]
+ {
+ new TestCaseData(new MultiThreadLazy(() => globalFunctionsForTestsForSingleThread.FunctionForLazyWithCounter())),
+ new TestCaseData(new SingleThreadLazy(() => globalFunctionsForTestsForMultiThread.FunctionForLazyWithCounter())),
+ };
+
+ private static IEnumerable LazyForTestWithFunctionWithException
+ => new TestCaseData[]
+ {
+ new TestCaseData(new SingleThreadLazy(() => globalFunctionsForTestsForSingleThread.DivideByZeroException())),
+ new TestCaseData(new MultiThreadLazy(() => globalFunctionsForTestsForMultiThread.DivideByZeroException())),
+ };
+}
\ No newline at end of file
diff --git a/Lazy/TestsForLazy/TestsForLazy.csproj b/Lazy/TestsForLazy/TestsForLazy.csproj
new file mode 100644
index 0000000..70890c4
--- /dev/null
+++ b/Lazy/TestsForLazy/TestsForLazy.csproj
@@ -0,0 +1,23 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Lazy/TestsForLazy/Usings.cs b/Lazy/TestsForLazy/Usings.cs
new file mode 100644
index 0000000..cefced4
--- /dev/null
+++ b/Lazy/TestsForLazy/Usings.cs
@@ -0,0 +1 @@
+global using NUnit.Framework;
\ No newline at end of file