diff --git a/Lazy/Lazy/Lazy.sln b/Lazy/Lazy/Lazy.sln
new file mode 100644
index 0000000..b4863d0
--- /dev/null
+++ b/Lazy/Lazy/Lazy.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.2.32505.173
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LazyTest", "LazyTest\LazyTest.csproj", "{47362B64-59D5-4275-B189-4AE547D1B8A9}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lazy", "Lazy\Lazy.csproj", "{0067E211-7EEC-40BB-AF0E-B3E2BFE38A83}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {47362B64-59D5-4275-B189-4AE547D1B8A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {47362B64-59D5-4275-B189-4AE547D1B8A9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {47362B64-59D5-4275-B189-4AE547D1B8A9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {47362B64-59D5-4275-B189-4AE547D1B8A9}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0067E211-7EEC-40BB-AF0E-B3E2BFE38A83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0067E211-7EEC-40BB-AF0E-B3E2BFE38A83}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0067E211-7EEC-40BB-AF0E-B3E2BFE38A83}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0067E211-7EEC-40BB-AF0E-B3E2BFE38A83}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {1DDBE986-F70C-460F-BAC3-5E300605253C}
+ EndGlobalSection
+EndGlobal
diff --git a/Lazy/Lazy/Lazy/ILazy.cs b/Lazy/Lazy/Lazy/ILazy.cs
new file mode 100644
index 0000000..6320658
--- /dev/null
+++ b/Lazy/Lazy/Lazy/ILazy.cs
@@ -0,0 +1,14 @@
+namespace Lazy;
+
+///
+/// Interface representing lazy computation
+///
+/// Element type
+public interface ILazy
+{
+ ///
+ /// Function that calls the calculation and returns the result
+ ///
+ /// Returns the result of the called function
+ T? Get();
+}
diff --git a/Lazy/Lazy/Lazy/Lazy.cs b/Lazy/Lazy/Lazy/Lazy.cs
new file mode 100644
index 0000000..e0bfc9e
--- /dev/null
+++ b/Lazy/Lazy/Lazy/Lazy.cs
@@ -0,0 +1,27 @@
+namespace Lazy;
+
+///
+/// Abstract class, for subsequent implementation of the ILazy interface
+///
+/// Element type
+public abstract class Lazy : ILazy
+{
+ protected Func? func;
+ protected T? value;
+
+ ///
+ /// Сonstructor
+ ///
+ /// The object on the basis of which the calculation is performed
+ public Lazy(Func func)
+ {
+ this.func = func;
+ }
+
+ ///
+ /// Function that calls a calculation and returns results
+ ///
+ /// Element type
+ public abstract T? Get();
+}
+
diff --git a/Lazy/Lazy/Lazy/Lazy.csproj b/Lazy/Lazy/Lazy/Lazy.csproj
new file mode 100644
index 0000000..16e62dd
--- /dev/null
+++ b/Lazy/Lazy/Lazy/Lazy.csproj
@@ -0,0 +1,10 @@
+
+
+
+ Library
+ net6.0
+ enable
+ enable
+
+
+
diff --git a/Lazy/Lazy/Lazy/MultithreadedLazy.cs b/Lazy/Lazy/Lazy/MultithreadedLazy.cs
new file mode 100644
index 0000000..773a53d
--- /dev/null
+++ b/Lazy/Lazy/Lazy/MultithreadedLazy.cs
@@ -0,0 +1,48 @@
+namespace Lazy;
+
+///
+/// Multithreaded implementation of Lazy
+///
+/// Element type
+public class MultithreadedLazy : Lazy
+{
+ ///
+ /// Boolean variable for detecting the first call
+ ///
+ private bool isAlreadyCounted;
+
+ ///
+ /// Lock
+ ///
+ private readonly object lockObject = new();
+
+ ///
+ public MultithreadedLazy(Func func) : base(func) { }
+
+ ///
+ public override T? Get()
+ {
+ // if the value has already been calculated, there should be no locks
+ if (!Volatile.Read(ref isAlreadyCounted))
+ {
+ // lock
+ lock (lockObject)
+ {
+ // if the value was not calculated
+ if (!Volatile.Read(ref isAlreadyCounted))
+ {
+ if (func == null)
+ {
+ throw new InvalidOperationException();
+ }
+
+ value = func();
+ func = null;
+ Volatile.Write(ref isAlreadyCounted, true);
+ }
+ }
+ }
+
+ return value;
+ }
+}
\ No newline at end of file
diff --git a/Lazy/Lazy/Lazy/SingleThreadedLazy.cs b/Lazy/Lazy/Lazy/SingleThreadedLazy.cs
new file mode 100644
index 0000000..135c668
--- /dev/null
+++ b/Lazy/Lazy/Lazy/SingleThreadedLazy.cs
@@ -0,0 +1,30 @@
+namespace Lazy;
+
+///
+/// Singlethreaded implementation of Lazy
+///
+/// Element type
+public class SingleThreadedLazy : Lazy
+{
+ ///
+ public SingleThreadedLazy(Func func) : base(func) { }
+
+ private bool isAlreadyCounted;
+
+ ///
+ public override T? Get()
+ {
+ if (!isAlreadyCounted)
+ {
+ if (func == null)
+ {
+ throw new InvalidOperationException();
+ }
+
+ value = func();
+ isAlreadyCounted = true;
+ }
+
+ return value;
+ }
+}
diff --git a/Lazy/Lazy/LazyTest/LazyTest.cs b/Lazy/Lazy/LazyTest/LazyTest.cs
new file mode 100644
index 0000000..276dfb6
--- /dev/null
+++ b/Lazy/Lazy/LazyTest/LazyTest.cs
@@ -0,0 +1,52 @@
+namespace LazyTest;
+
+public class LazyTests
+{
+ private static IEnumerable CaseData()
+ {
+ var values = new List { 0, -1, 1 };
+ int number = 0;
+
+ static int Increment(int number) => number + 1;
+
+ yield return new TestCaseData(new Lazy.SingleThreadedLazy(() => Increment(number)), 1);
+
+ foreach (var value in values)
+ {
+ yield return new TestCaseData(new Lazy.SingleThreadedLazy(() => value), value);
+ yield return new TestCaseData(new Lazy.MultithreadedLazy(() => value), value);
+ }
+ }
+
+ [TestCaseSource(nameof(CaseData))]
+ public void ShouldValueNotChangeForLazyInSinglethreadedMode(Lazy.ILazy lazy, int expectedValue)
+ {
+ for (int i = 0; i < 10; i++)
+ {
+ Assert.That(lazy.Get(), Is.EqualTo(expectedValue));
+ }
+ }
+
+ [Test]
+ public void ShouldValueNotChangeForLazyInMultithreadedMode()
+ {
+ static int Increment(int number) => Interlocked.Increment(ref number);
+ Lazy.ILazy lazy = new Lazy.MultithreadedLazy(() => Increment(0));
+ var threads = new Thread[8];
+
+ for (int i = 0; i < 8; i++)
+ {
+ threads[i] = new Thread(() => Assert.That(lazy.Get(), Is.EqualTo(1)));
+ }
+
+ foreach (var thread in threads)
+ {
+ thread.Start();
+ }
+
+ foreach (var thread in threads)
+ {
+ thread.Join();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Lazy/Lazy/LazyTest/LazyTest.csproj b/Lazy/Lazy/LazyTest/LazyTest.csproj
new file mode 100644
index 0000000..00642fd
--- /dev/null
+++ b/Lazy/Lazy/LazyTest/LazyTest.csproj
@@ -0,0 +1,23 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Lazy/Lazy/LazyTest/Usings.cs b/Lazy/Lazy/LazyTest/Usings.cs
new file mode 100644
index 0000000..cefced4
--- /dev/null
+++ b/Lazy/Lazy/LazyTest/Usings.cs
@@ -0,0 +1 @@
+global using NUnit.Framework;
\ No newline at end of file