From e7f347a1cf54867cd0b4d5e5c9d9dfe3a0728846 Mon Sep 17 00:00:00 2001 From: khusainovilas Date: Sun, 21 Sep 2025 23:37:41 +0300 Subject: [PATCH 01/16] init implementation of ILazy --- HW2/.idea/.idea.HW2/.idea/.gitignore | 13 +++++ HW2/.idea/.idea.HW2/.idea/encodings.xml | 4 ++ HW2/.idea/.idea.HW2/.idea/indexLayout.xml | 8 +++ .../.idea/material_theme_project_new.xml | 10 ++++ HW2/.idea/.idea.HW2/.idea/vcs.xml | 6 ++ HW2/HW2.sln | 22 ++++++++ HW2/LazyEvaluation/ILazy.cs | 18 ++++++ HW2/LazyEvaluation/LazyEvaluation.csproj | 21 +++++++ HW2/LazyEvaluation/LazyMultiThreaded.cs | 55 +++++++++++++++++++ HW2/LazyEvaluation/LazySingleThreaded.cs | 44 +++++++++++++++ HW2/LazyEvaluation/Program.cs | 3 + HW2/LazyEvaluation/stylecop.json | 9 +++ .../LazyEvalution.Test.csproj | 24 ++++++++ HW2/LazyEvalution.Test/UnitTest1.cs | 15 +++++ HW2/global.json | 7 +++ 15 files changed, 259 insertions(+) create mode 100644 HW2/.idea/.idea.HW2/.idea/.gitignore create mode 100644 HW2/.idea/.idea.HW2/.idea/encodings.xml create mode 100644 HW2/.idea/.idea.HW2/.idea/indexLayout.xml create mode 100644 HW2/.idea/.idea.HW2/.idea/material_theme_project_new.xml create mode 100644 HW2/.idea/.idea.HW2/.idea/vcs.xml create mode 100644 HW2/HW2.sln create mode 100644 HW2/LazyEvaluation/ILazy.cs create mode 100644 HW2/LazyEvaluation/LazyEvaluation.csproj create mode 100644 HW2/LazyEvaluation/LazyMultiThreaded.cs create mode 100644 HW2/LazyEvaluation/LazySingleThreaded.cs create mode 100644 HW2/LazyEvaluation/Program.cs create mode 100644 HW2/LazyEvaluation/stylecop.json create mode 100644 HW2/LazyEvalution.Test/LazyEvalution.Test.csproj create mode 100644 HW2/LazyEvalution.Test/UnitTest1.cs create mode 100644 HW2/global.json diff --git a/HW2/.idea/.idea.HW2/.idea/.gitignore b/HW2/.idea/.idea.HW2/.idea/.gitignore new file mode 100644 index 0000000..13647e3 --- /dev/null +++ b/HW2/.idea/.idea.HW2/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/.idea.HW2.iml +/modules.xml +/contentModel.xml +/projectSettingsUpdater.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/HW2/.idea/.idea.HW2/.idea/encodings.xml b/HW2/.idea/.idea.HW2/.idea/encodings.xml new file mode 100644 index 0000000..df87cf9 --- /dev/null +++ b/HW2/.idea/.idea.HW2/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/HW2/.idea/.idea.HW2/.idea/indexLayout.xml b/HW2/.idea/.idea.HW2/.idea/indexLayout.xml new file mode 100644 index 0000000..7b08163 --- /dev/null +++ b/HW2/.idea/.idea.HW2/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/HW2/.idea/.idea.HW2/.idea/material_theme_project_new.xml b/HW2/.idea/.idea.HW2/.idea/material_theme_project_new.xml new file mode 100644 index 0000000..c667a1f --- /dev/null +++ b/HW2/.idea/.idea.HW2/.idea/material_theme_project_new.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/HW2/.idea/.idea.HW2/.idea/vcs.xml b/HW2/.idea/.idea.HW2/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/HW2/.idea/.idea.HW2/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/HW2/HW2.sln b/HW2/HW2.sln new file mode 100644 index 0000000..5c6da93 --- /dev/null +++ b/HW2/HW2.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LazyEvaluation", "LazyEvaluation\LazyEvaluation.csproj", "{D2A3863F-D69C-419E-9580-826C8718A7E5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LazyEvalution.Test", "LazyEvalution.Test\LazyEvalution.Test.csproj", "{600A2318-54FE-4FF4-AE29-02FFA293A7E6}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D2A3863F-D69C-419E-9580-826C8718A7E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D2A3863F-D69C-419E-9580-826C8718A7E5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D2A3863F-D69C-419E-9580-826C8718A7E5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D2A3863F-D69C-419E-9580-826C8718A7E5}.Release|Any CPU.Build.0 = Release|Any CPU + {600A2318-54FE-4FF4-AE29-02FFA293A7E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {600A2318-54FE-4FF4-AE29-02FFA293A7E6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {600A2318-54FE-4FF4-AE29-02FFA293A7E6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {600A2318-54FE-4FF4-AE29-02FFA293A7E6}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/HW2/LazyEvaluation/ILazy.cs b/HW2/LazyEvaluation/ILazy.cs new file mode 100644 index 0000000..d9059e1 --- /dev/null +++ b/HW2/LazyEvaluation/ILazy.cs @@ -0,0 +1,18 @@ +// +// Copyright (c) khusainovilas. All rights reserved. +// + +namespace LazyEvaluation; + +/// +/// Defines a contract for lazy evaluation, where a value of type T is computed only on the first call and cached for subsequent access. +/// +/// The type of the value to be lazily computed. +public interface ILazy +{ + /// + /// Gets the lazily computed value. The value is computed on the first call and cached for subsequent calls. + /// + /// The computed or cached value. + T Get(); +} \ No newline at end of file diff --git a/HW2/LazyEvaluation/LazyEvaluation.csproj b/HW2/LazyEvaluation/LazyEvaluation.csproj new file mode 100644 index 0000000..796d45e --- /dev/null +++ b/HW2/LazyEvaluation/LazyEvaluation.csproj @@ -0,0 +1,21 @@ + + + + Exe + net8.0 + enable + enable + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + diff --git a/HW2/LazyEvaluation/LazyMultiThreaded.cs b/HW2/LazyEvaluation/LazyMultiThreaded.cs new file mode 100644 index 0000000..4438714 --- /dev/null +++ b/HW2/LazyEvaluation/LazyMultiThreaded.cs @@ -0,0 +1,55 @@ +// +// Copyright (c) khusainovilas. All rights reserved. +// + +namespace LazyEvaluation; + +/// +/// A multi-threaded implementation of the ILazy interface for lazy evaluation. +/// +/// The type of the value produced by the lazy computation. +public class LazyMultiThreaded : ILazy +{ + private Func? supplier; + private T value; + private volatile bool isComputed; + private readonly object lockObject = new object(); + + /// + /// Initializes a new instance of the class. + /// + /// The delegate that produces the value when needed. + public LazyMultiThreaded(Func? supplier) + { + this.supplier = supplier ?? throw new ArgumentNullException(nameof(supplier)); + this.isComputed = false; + } + + /// + public T Get() + { + if (this.isComputed) + { + return this.value; + } + + lock (this.lockObject) + { + if (this.isComputed) + { + return this.value; + } + + var func = this.supplier; + if (func != null) + { + this.value = func(); + this.isComputed = true; + } + + this.supplier = null; + } + + return this.value; + } +} \ No newline at end of file diff --git a/HW2/LazyEvaluation/LazySingleThreaded.cs b/HW2/LazyEvaluation/LazySingleThreaded.cs new file mode 100644 index 0000000..bf77a47 --- /dev/null +++ b/HW2/LazyEvaluation/LazySingleThreaded.cs @@ -0,0 +1,44 @@ +// +// Copyright (c) khusainovilas. All rights reserved. +// + +namespace LazyEvaluation; + +/// +/// A single-threaded implementation of the ILazy interface for lazy evaluation. +/// +/// The type of the value produced by the lazy computation. +public class LazySingleThreaded : ILazy +{ + private Func? supplier; + private T value; + private bool isComputed; + + /// + /// Initializes a new instance of the class. + /// + /// The delegate that produces the value when needed. + public LazySingleThreaded(Func supplier) + { + this.supplier = supplier ?? throw new ArgumentNullException(nameof(supplier)); + this.isComputed = false; + } + + /// + public T Get() + { + if (this.isComputed) + { + return this.value; + } + + if (this.supplier != null) + { + this.value = this.supplier(); + this.isComputed = true; + } + + this.supplier = null; + return this.value; + } +} \ No newline at end of file diff --git a/HW2/LazyEvaluation/Program.cs b/HW2/LazyEvaluation/Program.cs new file mode 100644 index 0000000..e5dff12 --- /dev/null +++ b/HW2/LazyEvaluation/Program.cs @@ -0,0 +1,3 @@ +// See https://aka.ms/new-console-template for more information + +Console.WriteLine("Hello, World!"); \ No newline at end of file diff --git a/HW2/LazyEvaluation/stylecop.json b/HW2/LazyEvaluation/stylecop.json new file mode 100644 index 0000000..76c8e76 --- /dev/null +++ b/HW2/LazyEvaluation/stylecop.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", + "settings": { + "documentationRules": { + "companyName": "khusainovilas", + "copyrightText": "Copyright (c) {companyName}. All rights reserved." + } + } +} \ No newline at end of file diff --git a/HW2/LazyEvalution.Test/LazyEvalution.Test.csproj b/HW2/LazyEvalution.Test/LazyEvalution.Test.csproj new file mode 100644 index 0000000..39c01e6 --- /dev/null +++ b/HW2/LazyEvalution.Test/LazyEvalution.Test.csproj @@ -0,0 +1,24 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + diff --git a/HW2/LazyEvalution.Test/UnitTest1.cs b/HW2/LazyEvalution.Test/UnitTest1.cs new file mode 100644 index 0000000..df9dd42 --- /dev/null +++ b/HW2/LazyEvalution.Test/UnitTest1.cs @@ -0,0 +1,15 @@ +namespace LazyEvalution.Test; + +public class Tests +{ + [SetUp] + public void Setup() + { + } + + [Test] + public void Test1() + { + Assert.Pass(); + } +} \ No newline at end of file diff --git a/HW2/global.json b/HW2/global.json new file mode 100644 index 0000000..2ddda36 --- /dev/null +++ b/HW2/global.json @@ -0,0 +1,7 @@ +{ + "sdk": { + "version": "8.0.0", + "rollForward": "latestMinor", + "allowPrerelease": false + } +} \ No newline at end of file From 91a3a9afaca57a88d03f0f65b1f49454497f43d6 Mon Sep 17 00:00:00 2001 From: khusainovilas Date: Mon, 22 Sep 2025 17:54:50 +0300 Subject: [PATCH 02/16] add common unit test for lazy evaluation --- HW2/HW2.sln | 10 +-- .../LazyEvaluation.Test.csproj} | 16 ++++ HW2/LazyEvaluation.Test/LazyEvaluationTest.cs | 78 +++++++++++++++++++ HW2/LazyEvaluation.Test/stylecop.json | 9 +++ HW2/LazyEvaluation/ILazy.cs | 2 +- HW2/LazyEvaluation/LazyMultiThreaded.cs | 8 +- HW2/LazyEvaluation/LazySingleThreaded.cs | 4 +- HW2/LazyEvalution.Test/UnitTest1.cs | 15 ---- 8 files changed, 115 insertions(+), 27 deletions(-) rename HW2/{LazyEvalution.Test/LazyEvalution.Test.csproj => LazyEvaluation.Test/LazyEvaluation.Test.csproj} (60%) create mode 100644 HW2/LazyEvaluation.Test/LazyEvaluationTest.cs create mode 100644 HW2/LazyEvaluation.Test/stylecop.json delete mode 100644 HW2/LazyEvalution.Test/UnitTest1.cs diff --git a/HW2/HW2.sln b/HW2/HW2.sln index 5c6da93..4045d39 100644 --- a/HW2/HW2.sln +++ b/HW2/HW2.sln @@ -2,7 +2,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LazyEvaluation", "LazyEvaluation\LazyEvaluation.csproj", "{D2A3863F-D69C-419E-9580-826C8718A7E5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LazyEvalution.Test", "LazyEvalution.Test\LazyEvalution.Test.csproj", "{600A2318-54FE-4FF4-AE29-02FFA293A7E6}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LazyEvaluation.Test", "LazyEvaluation.Test\LazyEvaluation.Test.csproj", "{C9B07A5A-EAD9-461C-B638-858E14BD4E7E}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -14,9 +14,9 @@ Global {D2A3863F-D69C-419E-9580-826C8718A7E5}.Debug|Any CPU.Build.0 = Debug|Any CPU {D2A3863F-D69C-419E-9580-826C8718A7E5}.Release|Any CPU.ActiveCfg = Release|Any CPU {D2A3863F-D69C-419E-9580-826C8718A7E5}.Release|Any CPU.Build.0 = Release|Any CPU - {600A2318-54FE-4FF4-AE29-02FFA293A7E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {600A2318-54FE-4FF4-AE29-02FFA293A7E6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {600A2318-54FE-4FF4-AE29-02FFA293A7E6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {600A2318-54FE-4FF4-AE29-02FFA293A7E6}.Release|Any CPU.Build.0 = Release|Any CPU + {C9B07A5A-EAD9-461C-B638-858E14BD4E7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C9B07A5A-EAD9-461C-B638-858E14BD4E7E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C9B07A5A-EAD9-461C-B638-858E14BD4E7E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C9B07A5A-EAD9-461C-B638-858E14BD4E7E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/HW2/LazyEvalution.Test/LazyEvalution.Test.csproj b/HW2/LazyEvaluation.Test/LazyEvaluation.Test.csproj similarity index 60% rename from HW2/LazyEvalution.Test/LazyEvalution.Test.csproj rename to HW2/LazyEvaluation.Test/LazyEvaluation.Test.csproj index 39c01e6..7cdccc1 100644 --- a/HW2/LazyEvalution.Test/LazyEvalution.Test.csproj +++ b/HW2/LazyEvaluation.Test/LazyEvaluation.Test.csproj @@ -21,4 +21,20 @@ + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + diff --git a/HW2/LazyEvaluation.Test/LazyEvaluationTest.cs b/HW2/LazyEvaluation.Test/LazyEvaluationTest.cs new file mode 100644 index 0000000..639e31d --- /dev/null +++ b/HW2/LazyEvaluation.Test/LazyEvaluationTest.cs @@ -0,0 +1,78 @@ +// +// Copyright (c) khusainovilas. All rights reserved. +// + +namespace LazyEvaluation.Test; + +using LazyEvaluation; + +/// +/// Unit tests for lazy evaluation. +/// +public abstract class LazyEvaluationTest +{ + /// + /// Verifies that the supplier is called exactly once. + /// + [Test] + public void Lazy_Get_SupplierCalledOnce() + { + var callCount = 0; + + var lazy = this.CreateLazy(Supplier); + + lazy.Get(); + lazy.Get(); + + Assert.That(callCount, Is.EqualTo(1)); + return; + + T Supplier() + { + callCount++; + return default!; + } + } + + /// + /// Verifies that multiple calls to Get() return the same result. + /// + [Test] + public void Lazy_Get_SameResult() + { + var lazy = this.CreateLazy(Supplier); + + var result1 = lazy.Get(); + var result2 = lazy.Get(); + + Assert.That(result2, Is.EqualTo(result1)); + return; + T? Supplier() => default; + } + + /// + /// Verifies that constructing with a null supplier throws ArgumentNullException. + /// + [Test] + public void Lazy_Constructor_NullSupplier_NonNullSupplier_ThrowsException() + { + Assert.Throws(() => this.CreateLazy(null)); + } + + /// + /// Verifies that Get() correctly handles a null result from the supplier. + /// + [Test] + public void Lazy_Get_String_NullSupplier_ReturnsNull() + { + var lazy = this.CreateLazy(Supplier); + + var result = lazy.Get(); + + Assert.That(result, Is.EqualTo(default(T))); + return; + T? Supplier() => default; + } + + protected abstract ILazy CreateLazy(Func? supplier); +} \ No newline at end of file diff --git a/HW2/LazyEvaluation.Test/stylecop.json b/HW2/LazyEvaluation.Test/stylecop.json new file mode 100644 index 0000000..76c8e76 --- /dev/null +++ b/HW2/LazyEvaluation.Test/stylecop.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", + "settings": { + "documentationRules": { + "companyName": "khusainovilas", + "copyrightText": "Copyright (c) {companyName}. All rights reserved." + } + } +} \ No newline at end of file diff --git a/HW2/LazyEvaluation/ILazy.cs b/HW2/LazyEvaluation/ILazy.cs index d9059e1..071a739 100644 --- a/HW2/LazyEvaluation/ILazy.cs +++ b/HW2/LazyEvaluation/ILazy.cs @@ -14,5 +14,5 @@ public interface ILazy /// Gets the lazily computed value. The value is computed on the first call and cached for subsequent calls. /// /// The computed or cached value. - T Get(); + T? Get(); } \ No newline at end of file diff --git a/HW2/LazyEvaluation/LazyMultiThreaded.cs b/HW2/LazyEvaluation/LazyMultiThreaded.cs index 4438714..3cac6e9 100644 --- a/HW2/LazyEvaluation/LazyMultiThreaded.cs +++ b/HW2/LazyEvaluation/LazyMultiThreaded.cs @@ -5,15 +5,15 @@ namespace LazyEvaluation; /// -/// A multi-threaded implementation of the ILazy interface for lazy evaluation. +/// A multithreaded implementation of the ILazy interface for lazy evaluation. /// /// The type of the value produced by the lazy computation. public class LazyMultiThreaded : ILazy { + private readonly object lockObject = new object(); private Func? supplier; - private T value; + private T? value; private volatile bool isComputed; - private readonly object lockObject = new object(); /// /// Initializes a new instance of the class. @@ -26,7 +26,7 @@ public LazyMultiThreaded(Func? supplier) } /// - public T Get() + public T? Get() { if (this.isComputed) { diff --git a/HW2/LazyEvaluation/LazySingleThreaded.cs b/HW2/LazyEvaluation/LazySingleThreaded.cs index bf77a47..42c5ba6 100644 --- a/HW2/LazyEvaluation/LazySingleThreaded.cs +++ b/HW2/LazyEvaluation/LazySingleThreaded.cs @@ -11,7 +11,7 @@ namespace LazyEvaluation; public class LazySingleThreaded : ILazy { private Func? supplier; - private T value; + private T? value; private bool isComputed; /// @@ -25,7 +25,7 @@ public LazySingleThreaded(Func supplier) } /// - public T Get() + public T? Get() { if (this.isComputed) { diff --git a/HW2/LazyEvalution.Test/UnitTest1.cs b/HW2/LazyEvalution.Test/UnitTest1.cs deleted file mode 100644 index df9dd42..0000000 --- a/HW2/LazyEvalution.Test/UnitTest1.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace LazyEvalution.Test; - -public class Tests -{ - [SetUp] - public void Setup() - { - } - - [Test] - public void Test1() - { - Assert.Pass(); - } -} \ No newline at end of file From 5a236019559d4dbbd810f6b94e77d5375d072059 Mon Sep 17 00:00:00 2001 From: khusainovilas Date: Sat, 27 Sep 2025 21:48:03 +0300 Subject: [PATCH 03/16] add tests for commonality between two implementations --- .../.idea/material_theme_project_new.xml | 4 +- HW2/LazyEvaluation.Test/LazyEvaluationTest.cs | 51 ++++++++++++------- HW2/LazyEvaluation/LazyMultiThreaded.cs | 2 +- 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/HW2/.idea/.idea.HW2/.idea/material_theme_project_new.xml b/HW2/.idea/.idea.HW2/.idea/material_theme_project_new.xml index c667a1f..2f3a836 100644 --- a/HW2/.idea/.idea.HW2/.idea/material_theme_project_new.xml +++ b/HW2/.idea/.idea.HW2/.idea/material_theme_project_new.xml @@ -3,7 +3,9 @@ diff --git a/HW2/LazyEvaluation.Test/LazyEvaluationTest.cs b/HW2/LazyEvaluation.Test/LazyEvaluationTest.cs index 639e31d..28da51f 100644 --- a/HW2/LazyEvaluation.Test/LazyEvaluationTest.cs +++ b/HW2/LazyEvaluation.Test/LazyEvaluationTest.cs @@ -4,22 +4,21 @@ namespace LazyEvaluation.Test; -using LazyEvaluation; - /// /// Unit tests for lazy evaluation. /// -public abstract class LazyEvaluationTest +public abstract class LazyEvaluationTest { /// - /// Verifies that the supplier is called exactly once. + /// Verifies that the supplier delegate is called exactly one time. /// [Test] - public void Lazy_Get_SupplierCalledOnce() + public void Lazy_Get_NonNullSupplier_SupplierCalledOnce() { var callCount = 0; - var lazy = this.CreateLazy(Supplier); + var supplier = new Func(Supplier); + var lazy = this.CreateLazy(supplier); lazy.Get(); lazy.Get(); @@ -27,10 +26,10 @@ public void Lazy_Get_SupplierCalledOnce() Assert.That(callCount, Is.EqualTo(1)); return; - T Supplier() + string Supplier() { callCount++; - return default!; + return "test"; } } @@ -38,41 +37,57 @@ T Supplier() /// Verifies that multiple calls to Get() return the same result. /// [Test] - public void Lazy_Get_SameResult() + public void Lazy_Get_SimpleString_NonNullSupplier_SameResult() { - var lazy = this.CreateLazy(Supplier); + var supplier = new Func(Supplier); + var lazy = this.CreateLazy(supplier); var result1 = lazy.Get(); var result2 = lazy.Get(); Assert.That(result2, Is.EqualTo(result1)); return; - T? Supplier() => default; + + string Supplier() + { + return "test"; + } } /// /// Verifies that constructing with a null supplier throws ArgumentNullException. /// [Test] - public void Lazy_Constructor_NullSupplier_NonNullSupplier_ThrowsException() + public void Lazy_Constructor_NullSupplier_ThrowsException() { - Assert.Throws(() => this.CreateLazy(null)); + Assert.Throws(() => this.CreateLazy(null)); } /// /// Verifies that Get() correctly handles a null result from the supplier. /// [Test] - public void Lazy_Get_String_NullSupplier_ReturnsNull() + public void Lazy_Get_NullResultSupplier_ReturnsNull() { - var lazy = this.CreateLazy(Supplier); + var supplier = new Func(Supplier); + var lazy = this.CreateLazy(supplier); var result = lazy.Get(); - Assert.That(result, Is.EqualTo(default(T))); + Assert.That(result, Is.Null); return; - T? Supplier() => default; + + string Supplier() + { + return null; + } } - protected abstract ILazy CreateLazy(Func? supplier); + /// + /// abstract method for creating an ILazy instance. + /// + /// function responsible for computing the value. + /// the type of the computed value. + /// a new ILazy instance. + protected abstract ILazy CreateLazy(Func supplier); } \ No newline at end of file diff --git a/HW2/LazyEvaluation/LazyMultiThreaded.cs b/HW2/LazyEvaluation/LazyMultiThreaded.cs index 3cac6e9..5f4cae6 100644 --- a/HW2/LazyEvaluation/LazyMultiThreaded.cs +++ b/HW2/LazyEvaluation/LazyMultiThreaded.cs @@ -10,7 +10,7 @@ namespace LazyEvaluation; /// The type of the value produced by the lazy computation. public class LazyMultiThreaded : ILazy { - private readonly object lockObject = new object(); + private readonly object lockObject = new(); private Func? supplier; private T? value; private volatile bool isComputed; From 200487796cdb4faf6899b5f07c0385ba381b2612 Mon Sep 17 00:00:00 2001 From: khusainovilas Date: Sat, 27 Sep 2025 21:55:29 +0300 Subject: [PATCH 04/16] add files for 2 tests --- HW2/LazyEvaluation.Test/LazyMultiThreadedTest.cs | 6 ++++++ HW2/LazyEvaluation.Test/LazySingleThreadedTest.cs | 6 ++++++ 2 files changed, 12 insertions(+) create mode 100644 HW2/LazyEvaluation.Test/LazyMultiThreadedTest.cs create mode 100644 HW2/LazyEvaluation.Test/LazySingleThreadedTest.cs diff --git a/HW2/LazyEvaluation.Test/LazyMultiThreadedTest.cs b/HW2/LazyEvaluation.Test/LazyMultiThreadedTest.cs new file mode 100644 index 0000000..b7c4aff --- /dev/null +++ b/HW2/LazyEvaluation.Test/LazyMultiThreadedTest.cs @@ -0,0 +1,6 @@ +namespace LazyEvaluation.Test; + +public class LazyMultiThreadedTest +{ + +} \ No newline at end of file diff --git a/HW2/LazyEvaluation.Test/LazySingleThreadedTest.cs b/HW2/LazyEvaluation.Test/LazySingleThreadedTest.cs new file mode 100644 index 0000000..9853f71 --- /dev/null +++ b/HW2/LazyEvaluation.Test/LazySingleThreadedTest.cs @@ -0,0 +1,6 @@ +namespace LazyEvaluation.Test; + +public class LazySingleThreadedTest +{ + +} \ No newline at end of file From 2d64352a773d59a75f6bdc6fc24f9ff445dfa616 Mon Sep 17 00:00:00 2001 From: khusainovilas Date: Sat, 27 Sep 2025 23:03:47 +0300 Subject: [PATCH 05/16] remove .idea folder and fix gitignore --- .gitignore | Bin 7370 -> 7386 bytes HW2/.idea/.idea.HW2/.idea/.gitignore | 13 ------------- HW2/.idea/.idea.HW2/.idea/encodings.xml | 4 ---- HW2/.idea/.idea.HW2/.idea/indexLayout.xml | 8 -------- .../.idea/material_theme_project_new.xml | 12 ------------ HW2/.idea/.idea.HW2/.idea/vcs.xml | 6 ------ 6 files changed, 43 deletions(-) delete mode 100644 HW2/.idea/.idea.HW2/.idea/.gitignore delete mode 100644 HW2/.idea/.idea.HW2/.idea/encodings.xml delete mode 100644 HW2/.idea/.idea.HW2/.idea/indexLayout.xml delete mode 100644 HW2/.idea/.idea.HW2/.idea/material_theme_project_new.xml delete mode 100644 HW2/.idea/.idea.HW2/.idea/vcs.xml diff --git a/.gitignore b/.gitignore index ce892922f7b0c014817dca8eb95a3b444d0bd27c..bac8c69e3d16ff1329a1cc0ec259d4f26187f401 100644 GIT binary patch delta 24 fcmX?QdCPLcDH#DhhD?SOhE#?`27Lxz1}+8wWdH@l delta 7 Ocmca*dCGFbDH#9{=>x3* diff --git a/HW2/.idea/.idea.HW2/.idea/.gitignore b/HW2/.idea/.idea.HW2/.idea/.gitignore deleted file mode 100644 index 13647e3..0000000 --- a/HW2/.idea/.idea.HW2/.idea/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Rider ignored files -/.idea.HW2.iml -/modules.xml -/contentModel.xml -/projectSettingsUpdater.xml -# Editor-based HTTP Client requests -/httpRequests/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml diff --git a/HW2/.idea/.idea.HW2/.idea/encodings.xml b/HW2/.idea/.idea.HW2/.idea/encodings.xml deleted file mode 100644 index df87cf9..0000000 --- a/HW2/.idea/.idea.HW2/.idea/encodings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/HW2/.idea/.idea.HW2/.idea/indexLayout.xml b/HW2/.idea/.idea.HW2/.idea/indexLayout.xml deleted file mode 100644 index 7b08163..0000000 --- a/HW2/.idea/.idea.HW2/.idea/indexLayout.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/HW2/.idea/.idea.HW2/.idea/material_theme_project_new.xml b/HW2/.idea/.idea.HW2/.idea/material_theme_project_new.xml deleted file mode 100644 index 2f3a836..0000000 --- a/HW2/.idea/.idea.HW2/.idea/material_theme_project_new.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/HW2/.idea/.idea.HW2/.idea/vcs.xml b/HW2/.idea/.idea.HW2/.idea/vcs.xml deleted file mode 100644 index 6c0b863..0000000 --- a/HW2/.idea/.idea.HW2/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file From 27c43151d74ce31527628d0efe7962410cb59d69 Mon Sep 17 00:00:00 2001 From: khusainovilas Date: Sat, 27 Sep 2025 23:31:05 +0300 Subject: [PATCH 06/16] add singleThreaded tests --- .../LazySingleThreadedTest.cs | 46 +++++++++++++++++-- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/HW2/LazyEvaluation.Test/LazySingleThreadedTest.cs b/HW2/LazyEvaluation.Test/LazySingleThreadedTest.cs index 9853f71..f0ec066 100644 --- a/HW2/LazyEvaluation.Test/LazySingleThreadedTest.cs +++ b/HW2/LazyEvaluation.Test/LazySingleThreadedTest.cs @@ -1,6 +1,46 @@ -namespace LazyEvaluation.Test; +// +// Copyright (c) khusainovilas. All rights reserved. +// -public class LazySingleThreadedTest +namespace LazyEvaluation.Test; + +/// +/// Unit tests for LazySingleThreaded implementation. +/// +public class LazySingleThreadedTest : LazyEvaluationTest { - + /// + /// Test for correct work Get() with double. + /// + [Test] + public void LazySingleThreaded_Get_Double_ReturnsCorrectValue() + { + var lazy = this.CreateLazy((Func)Supplier); + + var result = lazy.Get(); + + Assert.That(result, Is.EqualTo(42.5)); + return; + double Supplier() => 42.5; + } + + /// + /// Test for handling exception from supplier in Get(). + /// + [Test] + public void LazySingleThreaded_Get_Double_ThrowsException() + { + var lazy = this.CreateLazy((Func)Supplier); + + Assert.Throws(() => lazy.Get()); + return; + double Supplier() => throw new InvalidOperationException("Supplier failed"); + } + + /// + protected override ILazy CreateLazy(Func supplier) + where T : default + { + return new LazySingleThreaded(supplier!); + } } \ No newline at end of file From 451fec66ac9fa1e39d01d3ff3cacc24ad4dc347b Mon Sep 17 00:00:00 2001 From: khusainovilas Date: Tue, 30 Sep 2025 21:42:18 +0300 Subject: [PATCH 07/16] add multiThreaded tests --- .../LazyMultiThreadedTest.cs | 83 ++++++++++++++++++- 1 file changed, 80 insertions(+), 3 deletions(-) diff --git a/HW2/LazyEvaluation.Test/LazyMultiThreadedTest.cs b/HW2/LazyEvaluation.Test/LazyMultiThreadedTest.cs index b7c4aff..3839f5e 100644 --- a/HW2/LazyEvaluation.Test/LazyMultiThreadedTest.cs +++ b/HW2/LazyEvaluation.Test/LazyMultiThreadedTest.cs @@ -1,6 +1,83 @@ -namespace LazyEvaluation.Test; +// +// Copyright (c) khusainovilas. All rights reserved. +// -public class LazyMultiThreadedTest +namespace LazyEvaluation.Test; + +/// +/// Unit tests for LazyMultiThreaded implementation. +/// +public class LazyMultiThreadedTest : LazyEvaluationTest { - + /// + /// Verifies that the supplier is called exactly once during concurrent Get() calls in LazyMultiThreaded. + /// + [Test] + public void LazyMultiThreaded_Get_SimpleString_ConcurrentCalls_SingleSupplierCall() + { + var callCount = 0; + + var supplier = new Func(Supplier); + var lazy = this.CreateLazy(supplier); + const int taskCount = 10; + var tasks = new Task[taskCount]; + + for (var i = 0; i < taskCount; i++) + { + tasks[i] = Task.Run(() => lazy.Get()); + } + + Task.WhenAll(tasks).Wait(); + + Assert.That(callCount, Is.EqualTo(1)); + return; + + string Supplier() + { + callCount++; + return "test"; + } + } + + /// + /// Verifies that LazyMultiThreaded handles multiple concurrent calls without race conditions. + /// + [Test] + public void LazyMultiThreaded_Get_SimpleString_MultipleConcurrentCalls_NoRaceConditions() + { + var callCount = 0; + + var supplier = new Func(Supplier); + var lazy = this.CreateLazy(supplier); + const int taskCount = 100; + var tasks = new Task[taskCount]; + + for (var i = 0; i < taskCount; i++) + { + tasks[i] = Task.Run(() => lazy.Get())!; + } + + var results = Task.WhenAll(tasks).Result; + + Assert.That(callCount, Is.EqualTo(1)); + foreach (var result in results) + { + Assert.That(result, Is.EqualTo("test")); + } + + return; + + string Supplier() + { + callCount++; + return "test"; + } + } + + /// + protected override ILazy CreateLazy(Func supplier) + where T : default + { + return new LazyMultiThreaded(supplier!); + } } \ No newline at end of file From 7fa74bbaf312c19cdced6fe4e94b66f9a9ae8766 Mon Sep 17 00:00:00 2001 From: khusainovilas Date: Tue, 30 Sep 2025 21:53:45 +0300 Subject: [PATCH 08/16] change lazy multiThreaded tests --- .../LazyMultiThreadedTest.cs | 88 ++++++++++++------- 1 file changed, 54 insertions(+), 34 deletions(-) diff --git a/HW2/LazyEvaluation.Test/LazyMultiThreadedTest.cs b/HW2/LazyEvaluation.Test/LazyMultiThreadedTest.cs index 3839f5e..530baf9 100644 --- a/HW2/LazyEvaluation.Test/LazyMultiThreadedTest.cs +++ b/HW2/LazyEvaluation.Test/LazyMultiThreadedTest.cs @@ -13,30 +13,43 @@ public class LazyMultiThreadedTest : LazyEvaluationTest /// Verifies that the supplier is called exactly once during concurrent Get() calls in LazyMultiThreaded. /// [Test] - public void LazyMultiThreaded_Get_SimpleString_ConcurrentCalls_SingleSupplierCall() + public void LazyMultiThreaded_Get_String_SingleSupplierCall() { var callCount = 0; + var lazy = this.CreateLazy(() => + { + Interlocked.Increment(ref callCount); + return "test"; + }); - var supplier = new Func(Supplier); - var lazy = this.CreateLazy(supplier); - const int taskCount = 10; - var tasks = new Task[taskCount]; + const int threadsCount = 100; + var threads = new Thread[threadsCount]; + var results = new string[threadsCount]; - for (var i = 0; i < taskCount; i++) + for (var i = 0; i < threadsCount; i++) { - tasks[i] = Task.Run(() => lazy.Get()); + var index = i; + threads[i] = new Thread(() => + { + results[index] = lazy.Get() ?? string.Empty; + }); } - Task.WhenAll(tasks).Wait(); - - Assert.That(callCount, Is.EqualTo(1)); - return; + foreach (var thread in threads) + { + thread.Start(); + } - string Supplier() + foreach (var thread in threads) { - callCount++; - return "test"; + thread.Join(); } + + Assert.Multiple(() => + { + Assert.That(results, Has.All.EqualTo("test")); + Assert.That(callCount, Is.EqualTo(1)); + }); } /// @@ -46,38 +59,45 @@ string Supplier() public void LazyMultiThreaded_Get_SimpleString_MultipleConcurrentCalls_NoRaceConditions() { var callCount = 0; + var lazy = this.CreateLazy(() => + { + Interlocked.Increment(ref callCount); + return "test"; + }); - var supplier = new Func(Supplier); - var lazy = this.CreateLazy(supplier); - const int taskCount = 100; - var tasks = new Task[taskCount]; + const int threadsCount = 100; + var threads = new Thread[threadsCount]; + var results = new string[threadsCount]; - for (var i = 0; i < taskCount; i++) + for (var i = 0; i < threadsCount; i++) { - tasks[i] = Task.Run(() => lazy.Get())!; + var index = i; + threads[i] = new Thread(() => + { + results[index] = lazy.Get(); + }); } - var results = Task.WhenAll(tasks).Result; - - Assert.That(callCount, Is.EqualTo(1)); - foreach (var result in results) + foreach (var thread in threads) { - Assert.That(result, Is.EqualTo("test")); + thread.Start(); } - return; - - string Supplier() + foreach (var thread in threads) { - callCount++; - return "test"; + thread.Join(); } + + Assert.Multiple(() => + { + Assert.That(results, Has.All.EqualTo("test")); + Assert.That(callCount, Is.EqualTo(1)); + }); } /// - protected override ILazy CreateLazy(Func supplier) - where T : default + protected override ILazy CreateLazy(Func supplier) { - return new LazyMultiThreaded(supplier!); + return new LazyMultiThreaded(supplier); } -} \ No newline at end of file +} From 9fe44fa4c97d1b3660bf912b97ae01dc4d0d219d Mon Sep 17 00:00:00 2001 From: khusainovilas Date: Thu, 9 Oct 2025 22:51:44 +0300 Subject: [PATCH 09/16] remove unnecessary files and make minor code update --- HW2/LazyEvaluation/Program.cs | 3 --- HW2/global.json | 7 ------- 2 files changed, 10 deletions(-) delete mode 100644 HW2/LazyEvaluation/Program.cs delete mode 100644 HW2/global.json diff --git a/HW2/LazyEvaluation/Program.cs b/HW2/LazyEvaluation/Program.cs deleted file mode 100644 index e5dff12..0000000 --- a/HW2/LazyEvaluation/Program.cs +++ /dev/null @@ -1,3 +0,0 @@ -// See https://aka.ms/new-console-template for more information - -Console.WriteLine("Hello, World!"); \ No newline at end of file diff --git a/HW2/global.json b/HW2/global.json deleted file mode 100644 index 2ddda36..0000000 --- a/HW2/global.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "sdk": { - "version": "8.0.0", - "rollForward": "latestMinor", - "allowPrerelease": false - } -} \ No newline at end of file From 8bd83ca669188450b10bf88fcc10388db61101d3 Mon Sep 17 00:00:00 2001 From: khusainovilas Date: Thu, 9 Oct 2025 22:57:49 +0300 Subject: [PATCH 10/16] fix CI problem --- HW2/LazyEvaluation/LazyEvaluation.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HW2/LazyEvaluation/LazyEvaluation.csproj b/HW2/LazyEvaluation/LazyEvaluation.csproj index 796d45e..82fd482 100644 --- a/HW2/LazyEvaluation/LazyEvaluation.csproj +++ b/HW2/LazyEvaluation/LazyEvaluation.csproj @@ -1,7 +1,7 @@  - Exe + Library net8.0 enable enable From 3869255cbc7043ad6e24761d57b0b06e288fc036 Mon Sep 17 00:00:00 2001 From: khusainovilas Date: Thu, 9 Oct 2025 23:03:35 +0300 Subject: [PATCH 11/16] make minor code update in tests --- HW2/LazyEvaluation.Test/LazyEvaluationTest.cs | 4 ++-- .../LazyMultiThreadedTest.cs | 11 +++++---- .../LazySingleThreadedTest.cs | 24 ++++++++++++++----- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/HW2/LazyEvaluation.Test/LazyEvaluationTest.cs b/HW2/LazyEvaluation.Test/LazyEvaluationTest.cs index 28da51f..e8305f7 100644 --- a/HW2/LazyEvaluation.Test/LazyEvaluationTest.cs +++ b/HW2/LazyEvaluation.Test/LazyEvaluationTest.cs @@ -77,7 +77,7 @@ public void Lazy_Get_NullResultSupplier_ReturnsNull() Assert.That(result, Is.Null); return; - string Supplier() + string? Supplier() { return null; } @@ -89,5 +89,5 @@ string Supplier() /// function responsible for computing the value. /// the type of the computed value. /// a new ILazy instance. - protected abstract ILazy CreateLazy(Func supplier); + protected abstract ILazy CreateLazy(Func? supplier); } \ No newline at end of file diff --git a/HW2/LazyEvaluation.Test/LazyMultiThreadedTest.cs b/HW2/LazyEvaluation.Test/LazyMultiThreadedTest.cs index 530baf9..062ef23 100644 --- a/HW2/LazyEvaluation.Test/LazyMultiThreadedTest.cs +++ b/HW2/LazyEvaluation.Test/LazyMultiThreadedTest.cs @@ -56,7 +56,7 @@ public void LazyMultiThreaded_Get_String_SingleSupplierCall() /// Verifies that LazyMultiThreaded handles multiple concurrent calls without race conditions. /// [Test] - public void LazyMultiThreaded_Get_SimpleString_MultipleConcurrentCalls_NoRaceConditions() + public void LazyMultiThreaded_Get_String_NoRaceConditions() { var callCount = 0; var lazy = this.CreateLazy(() => @@ -67,14 +67,14 @@ public void LazyMultiThreaded_Get_SimpleString_MultipleConcurrentCalls_NoRaceCon const int threadsCount = 100; var threads = new Thread[threadsCount]; - var results = new string[threadsCount]; + var results = new string?[threadsCount]; for (var i = 0; i < threadsCount; i++) { var index = i; threads[i] = new Thread(() => { - results[index] = lazy.Get(); + results[index] = lazy.Get()!; }); } @@ -96,8 +96,9 @@ public void LazyMultiThreaded_Get_SimpleString_MultipleConcurrentCalls_NoRaceCon } /// - protected override ILazy CreateLazy(Func supplier) + protected override ILazy CreateLazy(Func? supplier) + where T : default { - return new LazyMultiThreaded(supplier); + return new LazyMultiThreaded(supplier); } } diff --git a/HW2/LazyEvaluation.Test/LazySingleThreadedTest.cs b/HW2/LazyEvaluation.Test/LazySingleThreadedTest.cs index f0ec066..13ffe90 100644 --- a/HW2/LazyEvaluation.Test/LazySingleThreadedTest.cs +++ b/HW2/LazyEvaluation.Test/LazySingleThreadedTest.cs @@ -15,13 +15,25 @@ public class LazySingleThreadedTest : LazyEvaluationTest [Test] public void LazySingleThreaded_Get_Double_ReturnsCorrectValue() { - var lazy = this.CreateLazy((Func)Supplier); + var callCount = 0; - var result = lazy.Get(); + var lazy = this.CreateLazy((Func)Supplier); + var result1 = lazy.Get(); + var result2 = lazy.Get(); // Второй вызов для проверки кэширования - Assert.That(result, Is.EqualTo(42.5)); + Assert.Multiple(() => + { + Assert.That(result1, Is.EqualTo(1.5)); + Assert.That(result2, Is.EqualTo(1.5)); + Assert.That(callCount, Is.EqualTo(1), "Supplier should be called exactly once."); + }); return; - double Supplier() => 42.5; + + double Supplier() + { + callCount++; + return 1.5; + } } /// @@ -38,9 +50,9 @@ public void LazySingleThreaded_Get_Double_ThrowsException() } /// - protected override ILazy CreateLazy(Func supplier) + protected override ILazy CreateLazy(Func? supplier) where T : default { - return new LazySingleThreaded(supplier!); + return new LazySingleThreaded(supplier!); } } \ No newline at end of file From 1963e0546e73c48625d412b28b99326decef0652 Mon Sep 17 00:00:00 2001 From: khusainovilas Date: Mon, 20 Oct 2025 15:34:37 +0300 Subject: [PATCH 12/16] fix: remove nullable types --- .../LazyMultiThreadedTest.cs | 5 ++-- .../LazySingleThreadedTest.cs | 5 ++-- HW2/LazyEvaluation/ILazy.cs | 2 +- HW2/LazyEvaluation/LazyMultiThreaded.cs | 27 +++++++------------ HW2/LazyEvaluation/LazySingleThreaded.cs | 21 +++++++-------- 5 files changed, 24 insertions(+), 36 deletions(-) diff --git a/HW2/LazyEvaluation.Test/LazyMultiThreadedTest.cs b/HW2/LazyEvaluation.Test/LazyMultiThreadedTest.cs index 062ef23..390fac3 100644 --- a/HW2/LazyEvaluation.Test/LazyMultiThreadedTest.cs +++ b/HW2/LazyEvaluation.Test/LazyMultiThreadedTest.cs @@ -96,9 +96,8 @@ public void LazyMultiThreaded_Get_String_NoRaceConditions() } /// - protected override ILazy CreateLazy(Func? supplier) - where T : default + protected override ILazy CreateLazy(Func supplier) { - return new LazyMultiThreaded(supplier); + return new LazySingleThreaded(supplier); } } diff --git a/HW2/LazyEvaluation.Test/LazySingleThreadedTest.cs b/HW2/LazyEvaluation.Test/LazySingleThreadedTest.cs index 13ffe90..a16a032 100644 --- a/HW2/LazyEvaluation.Test/LazySingleThreadedTest.cs +++ b/HW2/LazyEvaluation.Test/LazySingleThreadedTest.cs @@ -50,9 +50,8 @@ public void LazySingleThreaded_Get_Double_ThrowsException() } /// - protected override ILazy CreateLazy(Func? supplier) - where T : default + protected override ILazy CreateLazy(Func supplier) { - return new LazySingleThreaded(supplier!); + return new LazySingleThreaded(supplier); } } \ No newline at end of file diff --git a/HW2/LazyEvaluation/ILazy.cs b/HW2/LazyEvaluation/ILazy.cs index 071a739..d9059e1 100644 --- a/HW2/LazyEvaluation/ILazy.cs +++ b/HW2/LazyEvaluation/ILazy.cs @@ -14,5 +14,5 @@ public interface ILazy /// Gets the lazily computed value. The value is computed on the first call and cached for subsequent calls. /// /// The computed or cached value. - T? Get(); + T Get(); } \ No newline at end of file diff --git a/HW2/LazyEvaluation/LazyMultiThreaded.cs b/HW2/LazyEvaluation/LazyMultiThreaded.cs index 5f4cae6..2704915 100644 --- a/HW2/LazyEvaluation/LazyMultiThreaded.cs +++ b/HW2/LazyEvaluation/LazyMultiThreaded.cs @@ -11,45 +11,38 @@ namespace LazyEvaluation; public class LazyMultiThreaded : ILazy { private readonly object lockObject = new(); - private Func? supplier; + private Func supplier; private T? value; private volatile bool isComputed; - + /// /// Initializes a new instance of the class. /// /// The delegate that produces the value when needed. - public LazyMultiThreaded(Func? supplier) + public LazyMultiThreaded(Func supplier) { this.supplier = supplier ?? throw new ArgumentNullException(nameof(supplier)); this.isComputed = false; } - + /// - public T? Get() + public T Get() { if (this.isComputed) { - return this.value; + return this.value!; } lock (this.lockObject) { - if (this.isComputed) - { - return this.value; - } - - var func = this.supplier; - if (func != null) + if (!this.isComputed) { - this.value = func(); + this.value = this.supplier(); this.isComputed = true; + this.supplier = null!; } - - this.supplier = null; } - return this.value; + return this.value!; } } \ No newline at end of file diff --git a/HW2/LazyEvaluation/LazySingleThreaded.cs b/HW2/LazyEvaluation/LazySingleThreaded.cs index 42c5ba6..8833936 100644 --- a/HW2/LazyEvaluation/LazySingleThreaded.cs +++ b/HW2/LazyEvaluation/LazySingleThreaded.cs @@ -10,10 +10,10 @@ namespace LazyEvaluation; /// The type of the value produced by the lazy computation. public class LazySingleThreaded : ILazy { - private Func? supplier; + private Func supplier; private T? value; private bool isComputed; - + /// /// Initializes a new instance of the class. /// @@ -23,22 +23,19 @@ public LazySingleThreaded(Func supplier) this.supplier = supplier ?? throw new ArgumentNullException(nameof(supplier)); this.isComputed = false; } - + /// - public T? Get() + public T Get() { if (this.isComputed) { - return this.value; + return this.value!; } - if (this.supplier != null) - { - this.value = this.supplier(); - this.isComputed = true; - } + this.value = this.supplier(); + this.isComputed = true; + this.supplier = null!; - this.supplier = null; - return this.value; + return this.value!; } } \ No newline at end of file From 215d8e027a5967a2eb10481eb95df3b818827b93 Mon Sep 17 00:00:00 2001 From: khusainovilas Date: Mon, 20 Oct 2025 16:22:04 +0300 Subject: [PATCH 13/16] fix nullable mismatches --- HW2/LazyEvaluation.Test/LazyEvaluationTest.cs | 60 ++++++++++--------- .../LazyMultiThreadedTest.cs | 8 +-- .../LazySingleThreadedTest.cs | 22 +++---- HW2/LazyEvaluation/LazyMultiThreaded.cs | 16 ++--- HW2/LazyEvaluation/LazySingleThreaded.cs | 8 +-- 5 files changed, 57 insertions(+), 57 deletions(-) diff --git a/HW2/LazyEvaluation.Test/LazyEvaluationTest.cs b/HW2/LazyEvaluation.Test/LazyEvaluationTest.cs index e8305f7..304e3f9 100644 --- a/HW2/LazyEvaluation.Test/LazyEvaluationTest.cs +++ b/HW2/LazyEvaluation.Test/LazyEvaluationTest.cs @@ -17,20 +17,23 @@ public void Lazy_Get_NonNullSupplier_SupplierCalledOnce() { var callCount = 0; - var supplier = new Func(Supplier); - var lazy = this.CreateLazy(supplier); + var supplier = new Func(() => + { + callCount++; + return "test"; + }); - lazy.Get(); - lazy.Get(); + var lazy = this.CreateLazy(supplier); - Assert.That(callCount, Is.EqualTo(1)); - return; + var result1 = lazy.Get(); + var result2 = lazy.Get(); - string Supplier() + Assert.Multiple(() => { - callCount++; - return "test"; - } + Assert.That(result1, Is.EqualTo("test")); + Assert.That(result2, Is.EqualTo("test")); + Assert.That(callCount, Is.EqualTo(1)); + }); } /// @@ -39,19 +42,13 @@ string Supplier() [Test] public void Lazy_Get_SimpleString_NonNullSupplier_SameResult() { - var supplier = new Func(Supplier); + var supplier = new Func(() => "test"); var lazy = this.CreateLazy(supplier); var result1 = lazy.Get(); var result2 = lazy.Get(); Assert.That(result2, Is.EqualTo(result1)); - return; - - string Supplier() - { - return "test"; - } } /// @@ -60,7 +57,11 @@ string Supplier() [Test] public void Lazy_Constructor_NullSupplier_ThrowsException() { - Assert.Throws(() => this.CreateLazy(null)); + Assert.Throws(() => + { + Func supplier = null!; + this.CreateLazy(supplier); + }); } /// @@ -69,18 +70,21 @@ public void Lazy_Constructor_NullSupplier_ThrowsException() [Test] public void Lazy_Get_NullResultSupplier_ReturnsNull() { - var supplier = new Func(Supplier); - var lazy = this.CreateLazy(supplier); - - var result = lazy.Get(); + var callCount = 0; + var supplier = new Func(() => + { + callCount++; + return null; + }); - Assert.That(result, Is.Null); - return; + var lazy = this.CreateLazy(supplier); - string? Supplier() + Assert.Multiple(() => { - return null; - } + Assert.That(lazy.Get(), Is.Null); + Assert.That(lazy.Get(), Is.Null); + Assert.That(callCount, Is.EqualTo(1)); + }); } /// @@ -89,5 +93,5 @@ public void Lazy_Get_NullResultSupplier_ReturnsNull() /// function responsible for computing the value. /// the type of the computed value. /// a new ILazy instance. - protected abstract ILazy CreateLazy(Func? supplier); + protected abstract ILazy CreateLazy(Func supplier); } \ No newline at end of file diff --git a/HW2/LazyEvaluation.Test/LazyMultiThreadedTest.cs b/HW2/LazyEvaluation.Test/LazyMultiThreadedTest.cs index 390fac3..177850f 100644 --- a/HW2/LazyEvaluation.Test/LazyMultiThreadedTest.cs +++ b/HW2/LazyEvaluation.Test/LazyMultiThreadedTest.cs @@ -31,7 +31,7 @@ public void LazyMultiThreaded_Get_String_SingleSupplierCall() var index = i; threads[i] = new Thread(() => { - results[index] = lazy.Get() ?? string.Empty; + results[index] = lazy.Get(); }); } @@ -74,7 +74,7 @@ public void LazyMultiThreaded_Get_String_NoRaceConditions() var index = i; threads[i] = new Thread(() => { - results[index] = lazy.Get()!; + results[index] = lazy.Get(); }); } @@ -98,6 +98,6 @@ public void LazyMultiThreaded_Get_String_NoRaceConditions() /// protected override ILazy CreateLazy(Func supplier) { - return new LazySingleThreaded(supplier); + return new LazyMultiThreaded(supplier); } -} +} \ No newline at end of file diff --git a/HW2/LazyEvaluation.Test/LazySingleThreadedTest.cs b/HW2/LazyEvaluation.Test/LazySingleThreadedTest.cs index a16a032..33e06dd 100644 --- a/HW2/LazyEvaluation.Test/LazySingleThreadedTest.cs +++ b/HW2/LazyEvaluation.Test/LazySingleThreadedTest.cs @@ -16,24 +16,21 @@ public class LazySingleThreadedTest : LazyEvaluationTest public void LazySingleThreaded_Get_Double_ReturnsCorrectValue() { var callCount = 0; + var lazy = this.CreateLazy(() => + { + callCount++; + return 1.5; + }); - var lazy = this.CreateLazy((Func)Supplier); var result1 = lazy.Get(); - var result2 = lazy.Get(); // Второй вызов для проверки кэширования + var result2 = lazy.Get(); Assert.Multiple(() => { Assert.That(result1, Is.EqualTo(1.5)); Assert.That(result2, Is.EqualTo(1.5)); - Assert.That(callCount, Is.EqualTo(1), "Supplier should be called exactly once."); + Assert.That(callCount, Is.EqualTo(1)); }); - return; - - double Supplier() - { - callCount++; - return 1.5; - } } /// @@ -42,11 +39,8 @@ double Supplier() [Test] public void LazySingleThreaded_Get_Double_ThrowsException() { - var lazy = this.CreateLazy((Func)Supplier); - + var lazy = this.CreateLazy(() => throw new InvalidOperationException("Supplier failed")); Assert.Throws(() => lazy.Get()); - return; - double Supplier() => throw new InvalidOperationException("Supplier failed"); } /// diff --git a/HW2/LazyEvaluation/LazyMultiThreaded.cs b/HW2/LazyEvaluation/LazyMultiThreaded.cs index 2704915..d169942 100644 --- a/HW2/LazyEvaluation/LazyMultiThreaded.cs +++ b/HW2/LazyEvaluation/LazyMultiThreaded.cs @@ -11,10 +11,10 @@ namespace LazyEvaluation; public class LazyMultiThreaded : ILazy { private readonly object lockObject = new(); - private Func supplier; + private Func? supplier; private T? value; private volatile bool isComputed; - + /// /// Initializes a new instance of the class. /// @@ -24,7 +24,7 @@ public LazyMultiThreaded(Func supplier) this.supplier = supplier ?? throw new ArgumentNullException(nameof(supplier)); this.isComputed = false; } - + /// public T Get() { @@ -35,12 +35,14 @@ public T Get() lock (this.lockObject) { - if (!this.isComputed) + if (this.isComputed) { - this.value = this.supplier(); - this.isComputed = true; - this.supplier = null!; + return this.value!; } + + this.value = this.supplier!(); + this.isComputed = true; + this.supplier = null!; } return this.value!; diff --git a/HW2/LazyEvaluation/LazySingleThreaded.cs b/HW2/LazyEvaluation/LazySingleThreaded.cs index 8833936..92b08a7 100644 --- a/HW2/LazyEvaluation/LazySingleThreaded.cs +++ b/HW2/LazyEvaluation/LazySingleThreaded.cs @@ -10,10 +10,10 @@ namespace LazyEvaluation; /// The type of the value produced by the lazy computation. public class LazySingleThreaded : ILazy { - private Func supplier; + private Func? supplier; private T? value; private bool isComputed; - + /// /// Initializes a new instance of the class. /// @@ -23,7 +23,7 @@ public LazySingleThreaded(Func supplier) this.supplier = supplier ?? throw new ArgumentNullException(nameof(supplier)); this.isComputed = false; } - + /// public T Get() { @@ -32,7 +32,7 @@ public T Get() return this.value!; } - this.value = this.supplier(); + this.value = this.supplier!(); this.isComputed = true; this.supplier = null!; From 900056907b11f824f2a3d33bcdda14396815466d Mon Sep 17 00:00:00 2001 From: khusainovilas Date: Tue, 21 Oct 2025 20:46:09 +0300 Subject: [PATCH 14/16] Upgrade project to .NET 9 --- HW2/LazyEvaluation.Test/LazyEvaluation.Test.csproj | 2 +- HW2/LazyEvaluation/LazyEvaluation.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/HW2/LazyEvaluation.Test/LazyEvaluation.Test.csproj b/HW2/LazyEvaluation.Test/LazyEvaluation.Test.csproj index 7cdccc1..43a291d 100644 --- a/HW2/LazyEvaluation.Test/LazyEvaluation.Test.csproj +++ b/HW2/LazyEvaluation.Test/LazyEvaluation.Test.csproj @@ -1,7 +1,7 @@ - net8.0 + net9.0 enable enable diff --git a/HW2/LazyEvaluation/LazyEvaluation.csproj b/HW2/LazyEvaluation/LazyEvaluation.csproj index 82fd482..b158c23 100644 --- a/HW2/LazyEvaluation/LazyEvaluation.csproj +++ b/HW2/LazyEvaluation/LazyEvaluation.csproj @@ -2,7 +2,7 @@ Library - net8.0 + net9.0 enable enable From 09264355205f260a4744b05f87dfef3b20ff5eca Mon Sep 17 00:00:00 2001 From: khusainovilas Date: Wed, 7 Jan 2026 23:43:02 +0300 Subject: [PATCH 15/16] fix remarks --- .../LazyMultiThreadedTest.cs | 51 +++---------------- .../LazySingleThreadedTest.cs | 4 +- HW2/LazyEvaluation/LazyMultiThreaded.cs | 1 - 3 files changed, 8 insertions(+), 48 deletions(-) diff --git a/HW2/LazyEvaluation.Test/LazyMultiThreadedTest.cs b/HW2/LazyEvaluation.Test/LazyMultiThreadedTest.cs index 177850f..267a895 100644 --- a/HW2/LazyEvaluation.Test/LazyMultiThreadedTest.cs +++ b/HW2/LazyEvaluation.Test/LazyMultiThreadedTest.cs @@ -18,14 +18,16 @@ public void LazyMultiThreaded_Get_String_SingleSupplierCall() var callCount = 0; var lazy = this.CreateLazy(() => { - Interlocked.Increment(ref callCount); - return "test"; + Interlocked.Increment(ref callCount); + return "test"; }); const int threadsCount = 100; var threads = new Thread[threadsCount]; var results = new string[threadsCount]; + var startEvent = new ManualResetEvent(false); + for (var i = 0; i < threadsCount; i++) { var index = i; @@ -35,6 +37,8 @@ public void LazyMultiThreaded_Get_String_SingleSupplierCall() }); } + startEvent.Set(); + foreach (var thread in threads) { thread.Start(); @@ -52,49 +56,6 @@ public void LazyMultiThreaded_Get_String_SingleSupplierCall() }); } - /// - /// Verifies that LazyMultiThreaded handles multiple concurrent calls without race conditions. - /// - [Test] - public void LazyMultiThreaded_Get_String_NoRaceConditions() - { - var callCount = 0; - var lazy = this.CreateLazy(() => - { - Interlocked.Increment(ref callCount); - return "test"; - }); - - const int threadsCount = 100; - var threads = new Thread[threadsCount]; - var results = new string?[threadsCount]; - - for (var i = 0; i < threadsCount; i++) - { - var index = i; - threads[i] = new Thread(() => - { - results[index] = lazy.Get(); - }); - } - - foreach (var thread in threads) - { - thread.Start(); - } - - foreach (var thread in threads) - { - thread.Join(); - } - - Assert.Multiple(() => - { - Assert.That(results, Has.All.EqualTo("test")); - Assert.That(callCount, Is.EqualTo(1)); - }); - } - /// protected override ILazy CreateLazy(Func supplier) { diff --git a/HW2/LazyEvaluation.Test/LazySingleThreadedTest.cs b/HW2/LazyEvaluation.Test/LazySingleThreadedTest.cs index 33e06dd..7c0d4e5 100644 --- a/HW2/LazyEvaluation.Test/LazySingleThreadedTest.cs +++ b/HW2/LazyEvaluation.Test/LazySingleThreadedTest.cs @@ -27,8 +27,8 @@ public void LazySingleThreaded_Get_Double_ReturnsCorrectValue() Assert.Multiple(() => { - Assert.That(result1, Is.EqualTo(1.5)); - Assert.That(result2, Is.EqualTo(1.5)); + Assert.That(result1, Is.EqualTo(1.5).Within(1e-9)); + Assert.That(result2, Is.EqualTo(1.5).Within(1e-9)); Assert.That(callCount, Is.EqualTo(1)); }); } diff --git a/HW2/LazyEvaluation/LazyMultiThreaded.cs b/HW2/LazyEvaluation/LazyMultiThreaded.cs index d169942..62b5cd1 100644 --- a/HW2/LazyEvaluation/LazyMultiThreaded.cs +++ b/HW2/LazyEvaluation/LazyMultiThreaded.cs @@ -22,7 +22,6 @@ public class LazyMultiThreaded : ILazy public LazyMultiThreaded(Func supplier) { this.supplier = supplier ?? throw new ArgumentNullException(nameof(supplier)); - this.isComputed = false; } /// From a382fcd0b08f42b99ad24fec0e1f0e02a82b0c06 Mon Sep 17 00:00:00 2001 From: khusainovilas Date: Wed, 7 Jan 2026 23:46:34 +0300 Subject: [PATCH 16/16] fix remarks --- HW2/LazyEvaluation/LazySingleThreaded.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/HW2/LazyEvaluation/LazySingleThreaded.cs b/HW2/LazyEvaluation/LazySingleThreaded.cs index 92b08a7..b6490a1 100644 --- a/HW2/LazyEvaluation/LazySingleThreaded.cs +++ b/HW2/LazyEvaluation/LazySingleThreaded.cs @@ -21,7 +21,6 @@ public class LazySingleThreaded : ILazy public LazySingleThreaded(Func supplier) { this.supplier = supplier ?? throw new ArgumentNullException(nameof(supplier)); - this.isComputed = false; } ///