From b2e8ed9787157bb975a18f164e6c2a0b620b1d7f Mon Sep 17 00:00:00 2001 From: GeWuYou <95328647+GeWuYou@users.noreply.github.com> Date: Sat, 31 Jan 2026 22:31:50 +0800 Subject: [PATCH] =?UTF-8?q?refactor(functional):=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E5=BC=8F=E7=BC=96=E7=A8=8B=E6=89=A9=E5=B1=95?= =?UTF-8?q?=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除 EnumerableExtensions 扩展类及其 Map、Filter、Reduce 方法 - 从 ControlExtensions 中删除 Match、MatchOrDefault、If、IfElse 等控制流方法 - 重命名 FunctionExtensions 中的 Memoize 为 MemoizeUnbounded 并更新文档注释 - 重命名 FunctionExtensions 中的 Partial 相关方法并调整参数命名 - 在 PipeExtensions 中移除 Pipe、Then、After、Let 等方法,保留 Also 方法 - 删除多个功能性类型扩展文件,包括 Option、Result、NullableExtensions 等 - 移除功能扩展的 README.md 文档文件 - 更新相关命名空间引用和依赖关系 - [release ci] --- .../collections/EnumerableExtensionsTests.cs | 72 --- .../control/ControlExtensionsTests.cs | 174 +------- .../functions/FunctionExtensionsTests.cs | 134 +----- .../functional/pipe/PipeExtensionsTests.cs | 73 --- .../types/NullableExtensionsTests.cs | 78 ---- .../functional/types/OptionExtensionsTests.cs | 181 -------- .../functional/types/OptionTests.cs | 70 --- .../types/OptionValueExtensionsTests.cs | 141 ------ .../functional/types/ResultExtensionsTests.cs | 171 ------- .../functional/types/ResultTests.cs | 108 ----- .../functional/types/TypeExtensionsTests.cs | 69 --- GFramework.Core/GFramework.Core.csproj | 3 + GFramework.Core/GlobalUsings.cs | 5 +- .../coroutine/CoroutineScheduler.cs | 1 - GFramework.Core/functional/README.md | 421 ------------------ .../collections/EnumerableExtensions.cs | 59 --- .../functional/control/ControlExtensions.cs | 78 ---- .../functions/FunctionExtensions.cs | 125 ++---- .../functional/pipe/PipeExtensions.cs | 69 +-- .../functional/types/NullableExtensions.cs | 44 -- GFramework.Core/functional/types/Option.cs | 78 ---- .../functional/types/OptionExtensions.cs | 89 ---- .../functional/types/OptionValueExtensions.cs | 56 --- GFramework.Core/functional/types/Result.cs | 91 ---- .../functional/types/ResultExtensions.cs | 54 --- .../functional/types/TypeExtensions.cs | 44 -- GFramework.Game/GFramework.Game.csproj | 1 + GFramework.Game/GlobalUsings.cs | 5 +- GFramework.Godot/GFramework.Godot.csproj | 1 + GFramework.Godot/GlobalUsings.cs | 5 +- GFramework.Godot/storage/GodotFileStorage.cs | 1 + 31 files changed, 73 insertions(+), 2428 deletions(-) delete mode 100644 GFramework.Core.Tests/functional/collections/EnumerableExtensionsTests.cs delete mode 100644 GFramework.Core.Tests/functional/types/NullableExtensionsTests.cs delete mode 100644 GFramework.Core.Tests/functional/types/OptionExtensionsTests.cs delete mode 100644 GFramework.Core.Tests/functional/types/OptionTests.cs delete mode 100644 GFramework.Core.Tests/functional/types/OptionValueExtensionsTests.cs delete mode 100644 GFramework.Core.Tests/functional/types/ResultExtensionsTests.cs delete mode 100644 GFramework.Core.Tests/functional/types/ResultTests.cs delete mode 100644 GFramework.Core.Tests/functional/types/TypeExtensionsTests.cs delete mode 100644 GFramework.Core/functional/README.md delete mode 100644 GFramework.Core/functional/collections/EnumerableExtensions.cs delete mode 100644 GFramework.Core/functional/types/NullableExtensions.cs delete mode 100644 GFramework.Core/functional/types/Option.cs delete mode 100644 GFramework.Core/functional/types/OptionExtensions.cs delete mode 100644 GFramework.Core/functional/types/OptionValueExtensions.cs delete mode 100644 GFramework.Core/functional/types/Result.cs delete mode 100644 GFramework.Core/functional/types/ResultExtensions.cs delete mode 100644 GFramework.Core/functional/types/TypeExtensions.cs diff --git a/GFramework.Core.Tests/functional/collections/EnumerableExtensionsTests.cs b/GFramework.Core.Tests/functional/collections/EnumerableExtensionsTests.cs deleted file mode 100644 index 472e119..0000000 --- a/GFramework.Core.Tests/functional/collections/EnumerableExtensionsTests.cs +++ /dev/null @@ -1,72 +0,0 @@ -using GFramework.Core.functional.collections; -using NUnit.Framework; - -namespace GFramework.Core.Tests.functional.collections; - -/// -/// EnumerableExtensions扩展方法测试类,用于验证集合函数式编程扩展方法的正确性 -/// 包括Map、Filter、Reduce等集合操作功能的测试 -/// -[TestFixture] -public class EnumerableExtensionsTests -{ - #region Map Tests - - /// - /// 测试Map方法 - 验证集合中的每个元素都能被正确转换 - /// - [Test] - public void Map_Should_Transform_Each_Element_In_Collection() - { - // Arrange - var numbers = new[] {1, 2, 3, 4}; - - // Act - var result = numbers.Map(x => x * x).ToArray(); - - // Assert - Assert.That(result, Is.EquivalentTo([1, 4, 9, 16])); - } - - #endregion - - #region Filter Tests - - /// - /// 测试Filter方法 - 验证集合能够根据条件正确过滤 - /// - [Test] - public void Filter_Should_Filter_Elements_Based_On_Predicate() - { - // Arrange - var numbers = new[] {1, 2, 3, 4, 5, 6}; - - // Act - var result = numbers.Filter(x => x % 2 == 0).ToArray(); - - // Assert - Assert.That(result, Is.EquivalentTo([2, 4, 6])); - } - - #endregion - - #region Reduce Tests - - /// - /// 测试Reduce方法 - 验证集合能够正确归约为单个值 - /// - [Test] - public void Reduce_Should_Reduce_Collection_To_Single_Value() - { - // Arrange - var numbers = new[] {1, 2, 3, 4}; - - // Act - var result = numbers.Reduce(0, (acc, x) => acc + x); - - // Assert - Assert.That(result, Is.EqualTo(10)); - } - - #endregion -} \ No newline at end of file diff --git a/GFramework.Core.Tests/functional/control/ControlExtensionsTests.cs b/GFramework.Core.Tests/functional/control/ControlExtensionsTests.cs index ba5ab69..46d81e0 100644 --- a/GFramework.Core.Tests/functional/control/ControlExtensionsTests.cs +++ b/GFramework.Core.Tests/functional/control/ControlExtensionsTests.cs @@ -5,158 +5,10 @@ namespace GFramework.Core.Tests.functional.control; /// /// ControlExtensions扩展方法测试类,用于验证控制流函数式编程扩展方法的正确性 -/// 包括模式匹配、条件执行等控制流功能的测试 /// [TestFixture] public class ControlExtensionsTests { - #region Match Tests - - /// - /// 测试Match方法 - 验证模式匹配功能 - /// - [Test] - public void Match_Should_Execute_Matching_Case() - { - // Arrange - var value = 5; - - // Act - var result = value.Match( - (x => x < 0, _ => "negative"), - (x => x > 0, _ => "positive"), - (x => x == 0, _ => "zero") - ); - - // Assert - Assert.That(result, Is.EqualTo("positive")); - } - - /// - /// 测试Match方法 - 验证无匹配时抛出异常 - /// - [Test] - public void Match_Should_Throw_Exception_When_No_Case_Matches() - { - // Arrange - var value = 10; - - // Act & Assert - Assert.Throws(() => - value.Match( - (x => x < 0, _ => "negative"), - (x => x > 10, _ => "large positive") - ) - ); - } - - #endregion - - #region MatchOrDefault Tests - - /// - /// 测试MatchOrDefault方法 - 验证模式匹配带默认值功能 - /// - [Test] - public void MatchOrDefault_Should_Execute_Matching_Case_Or_Return_Default() - { - // Arrange - var value = 10; - - // Act - var result = value.MatchOrDefault("unknown", - (x => x < 0, _ => "negative"), - (x => x > 10, _ => "large positive") - ); - - // Assert - Assert.That(result, Is.EqualTo("unknown")); - } - - #endregion - - #region If Tests - - /// - /// 测试If方法 - 验证条件执行功能 - /// - [Test] - public void If_Should_Execute_ThenFunc_When_Condition_Is_True() - { - // Arrange - var value = 5; - - // Act - var result = value.If(x => x > 0, x => x * 2); - - // Assert - Assert.That(result, Is.EqualTo(10)); - } - - /// - /// 测试If方法 - 验证条件为假时不执行转换函数 - /// - [Test] - public void If_Should_Return_Original_Value_When_Condition_Is_False() - { - // Arrange - var value = -5; - - // Act - var result = value.If(x => x > 0, x => x * 2); - - // Assert - Assert.That(result, Is.EqualTo(-5)); - } - - #endregion - - #region IfElse Tests - - /// - /// 测试IfElse方法 - 验证条件分支功能 - /// - [Test] - public void IfElse_Should_Execute_ThenFunc_When_Condition_Is_True() - { - // Arrange - var value = 5; - - // Act - var result = value.IfElse( - x => x > 0, - x => x * 2, - x => x * -1 - ); - - // Assert - Assert.That(result, Is.EqualTo(10)); - } - - /// - /// 测试IfElse方法 - 验证条件为假时执行else分支 - /// - [Test] - public void IfElse_Should_Execute_ElseFunc_When_Condition_Is_False() - { - // Arrange - var value = -5; - - // Act - var result = value.IfElse( - x => x > 0, - x => x * 2, - x => x * -1 - ); - - // Assert - Assert.That(result, Is.EqualTo(5)); - } - - #endregion - - #region TakeIf Tests - /// /// 测试TakeIf方法 - 验证条件为真时返回原值 /// @@ -165,14 +17,14 @@ public class ControlExtensionsTests { // Arrange string str = "Hello"; - + // Act var result = str.TakeIf(s => s.Length > 3); - + // Assert Assert.That(result, Is.EqualTo("Hello")); } - + /// /// 测试TakeIf方法 - 验证条件为假时返回null /// @@ -181,18 +33,14 @@ public class ControlExtensionsTests { // Arrange string str = "Hi"; - + // Act var result = str.TakeIf(s => s.Length > 3); - + // Assert Assert.That(result, Is.Null); } - #endregion - - #region TakeUnless Tests - /// /// 测试TakeUnless方法 - 验证条件为假时返回原值 /// @@ -201,14 +49,14 @@ public class ControlExtensionsTests { // Arrange string str = "Hi"; - + // Act var result = str.TakeUnless(s => s.Length > 3); - + // Assert Assert.That(result, Is.EqualTo("Hi")); } - + /// /// 测试TakeUnless方法 - 验证条件为真时返回null /// @@ -217,13 +65,11 @@ public class ControlExtensionsTests { // Arrange string str = "Hello"; - + // Act var result = str.TakeUnless(s => s.Length > 3); - + // Assert Assert.That(result, Is.Null); } - - #endregion } \ No newline at end of file diff --git a/GFramework.Core.Tests/functional/functions/FunctionExtensionsTests.cs b/GFramework.Core.Tests/functional/functions/FunctionExtensionsTests.cs index 7b259cd..5544159 100644 --- a/GFramework.Core.Tests/functional/functions/FunctionExtensionsTests.cs +++ b/GFramework.Core.Tests/functional/functions/FunctionExtensionsTests.cs @@ -10,52 +10,6 @@ namespace GFramework.Core.Tests.functional.functions; [TestFixture] public class FunctionExtensionsTests { - #region Curry Tests - - /// - /// 测试Curry方法 - 验证二参数函数能够正确柯里化 - /// - [Test] - public void Curry_Should_Convert_Binary_Function_To_Curried_Form() - { - // Arrange - Func add = (x, y) => x + y; - - // Act - var curriedAdd = add.Curry(); - var addFive = curriedAdd(5); - var result = addFive(3); - - // Assert - Assert.That(result, Is.EqualTo(8)); - } - - #endregion - - #region Uncurry Tests - - /// - /// 测试Uncurry方法 - 验证柯里化函数能够正确还原为二参数函数 - /// - [Test] - public void Uncurry_Should_Convert_Curried_Function_Back_To_Binary_Form() - { - // Arrange - Func originalAdd = (x, y) => x + y; - var curriedAdd = originalAdd.Curry(); - - // Act - var uncurriedAdd = curriedAdd.Uncurry(); - var result = uncurriedAdd(5, 3); - - // Assert - Assert.That(result, Is.EqualTo(8)); - } - - #endregion - - #region Partial Tests - /// /// 测试Partial方法 - 验证部分应用函数功能 /// @@ -64,19 +18,15 @@ public class FunctionExtensionsTests { // Arrange Func multiply = (x, y) => x * y; - + // Act var doubleFunction = multiply.Partial(2); var result = doubleFunction(5); - + // Assert Assert.That(result, Is.EqualTo(10)); } - #endregion - - #region Repeat Tests - /// /// 测试Repeat方法 - 验证重复执行函数功能 /// @@ -85,88 +35,12 @@ public class FunctionExtensionsTests { // Arrange var initialValue = 2; - + // Act var result = initialValue.Repeat(3, x => x * 2); - + // Assert // 2 -> 4 -> 8 -> 16 (3次重复) Assert.That(result, Is.EqualTo(16)); } - - #endregion - - #region Try Tests - - /// - /// 测试Try方法 - 验证安全执行成功情况 - /// - [Test] - public void Try_Should_Return_Success_When_Function_Does_Not_Throw() - { - // Arrange - var value = 10; - - // Act - var (success, result, error) = value.Try(x => 100 / x); - - // Assert - Assert.That(success, Is.True); - Assert.That(result, Is.EqualTo(10)); - Assert.That(error, Is.Null); - } - - /// - /// 测试Try方法 - 验证安全执行异常情况 - /// - [Test] - public void Try_Should_Return_Failure_When_Function_Throws() - { - // Arrange - var value = 0; - - // Act - var (success, result, error) = value.Try(x => 100 / x); - - // Assert - Assert.That(success, Is.False); - Assert.That(result, Is.EqualTo(0)); // 对于int类型,默认值是0 - Assert.That(error, Is.Not.Null); - Assert.That(error, Is.TypeOf()); - } - - #endregion - - #region Memoize Tests - - /// - /// 测试Memoize方法 - 验证函数结果缓存功能 - /// - [Test] - public void Memoize_Should_Cache_Function_Results() - { - // Arrange - var callCount = 0; - Func expensiveFunction = x => - { - callCount++; - return x * x; - }; - var memoized = expensiveFunction.Memoize(); - - // Act - var result1 = memoized(5); // 第一次调用 - var result2 = memoized(5); // 第二次调用,应该使用缓存 - var result3 = memoized(3); // 新参数,应该调用函数 - var result4 = memoized(3); // 再次使用相同参数,应该使用缓存 - - // Assert - Assert.That(result1, Is.EqualTo(25)); - Assert.That(result2, Is.EqualTo(25)); - Assert.That(result3, Is.EqualTo(9)); - Assert.That(result4, Is.EqualTo(9)); - Assert.That(callCount, Is.EqualTo(2)); // 只应调用两次,而不是四次 - } - - #endregion } \ No newline at end of file diff --git a/GFramework.Core.Tests/functional/pipe/PipeExtensionsTests.cs b/GFramework.Core.Tests/functional/pipe/PipeExtensionsTests.cs index aca1386..c8c0327 100644 --- a/GFramework.Core.Tests/functional/pipe/PipeExtensionsTests.cs +++ b/GFramework.Core.Tests/functional/pipe/PipeExtensionsTests.cs @@ -10,63 +10,6 @@ namespace GFramework.Core.Tests.functional.pipe; [TestFixture] public class PipeExtensionsTests { - /// - /// 测试Pipe方法 - 验证值能够正确传递给函数并返回结果 - /// - [Test] - public void Pipe_Should_Execute_Function_And_Return_Result() - { - // Arrange - var value = 5; - - // Act - var result = value.Pipe(x => x * 2); - - // Assert - Assert.That(result, Is.EqualTo(10)); - } - - /// - /// 测试Then方法 - 验证两个函数能够正确组合执行 - /// - [Test] - public void Then_Should_Compose_Two_Functions() - { - // Arrange - Func addTwo = x => x + 2; - - // Act - var composed = addTwo.Then((Func)MultiplyByThree); - var result = composed(5); - - // Assert - Assert.That(result, Is.EqualTo(21)); // (5+2)*3 = 21 - return; - - int MultiplyByThree(int x) => x * 3; - } - - /// - /// 测试After方法 - 验证反向函数组合的正确性 - /// - [Test] - public void After_Should_Compose_Functions_In_Reversed_Order() - { - // Arrange - Func multiplyByThree = x => x * 3; - - // Act - var composed = multiplyByThree.After((Func)AddTwo); - var result = composed(5); - - // Assert - Assert.That(result, Is.EqualTo(21)); // (5+2)*3 = 21 - return; - - int AddTwo(int x) => x + 2; - } - - /// /// 测试Also方法 - 验证执行操作后返回原值功能 /// @@ -84,20 +27,4 @@ public class PipeExtensionsTests Assert.That(result, Is.EqualTo(42)); Assert.That(capturedValue, Is.EqualTo(42)); } - - /// - /// 测试Let方法 - 验证值转换功能 - /// - [Test] - public void Let_Should_Transform_Value() - { - // Arrange - var value = 5; - - // Act - var result = value.Let(x => x * 2); - - // Assert - Assert.That(result, Is.EqualTo(10)); - } } \ No newline at end of file diff --git a/GFramework.Core.Tests/functional/types/NullableExtensionsTests.cs b/GFramework.Core.Tests/functional/types/NullableExtensionsTests.cs deleted file mode 100644 index a518fb2..0000000 --- a/GFramework.Core.Tests/functional/types/NullableExtensionsTests.cs +++ /dev/null @@ -1,78 +0,0 @@ -using GFramework.Core.functional.types; -using NUnit.Framework; - -namespace GFramework.Core.Tests.functional.types; - -/// -/// NullableExtensions扩展方法测试类,用于验证可空类型转换为Option类型的功能 -/// 包括引用类型和值类型的可空转换测试 -/// -[TestFixture] -public class NullableExtensionsTests -{ - /// - /// 测试引用类型可空转换 - 验证非null值转换为Some - /// - [Test] - public void NullableExtensions_ReferenceType_ToOption_Should_Create_Some_For_NonNull() - { - // Arrange - string? value = "Hello"; - - // Act - var option = value.ToOption(); - - // Assert - Assert.That(option.IsSome, Is.True); - Assert.That(option.Value, Is.EqualTo("Hello")); - } - - /// - /// 测试引用类型可空转换 - 验证null值转换为None - /// - [Test] - public void NullableExtensions_ReferenceType_ToOption_Should_Create_None_For_Null() - { - // Arrange - string? value = null; - - // Act - var option = value.ToOption(); - - // Assert - Assert.That(option.IsNone, Is.True); - } - - /// - /// 测试值类型可空转换 - 验证有值的可空值类型转换为Some - /// - [Test] - public void NullableExtensions_ValueType_ToOption_Should_Create_Some_For_HasValue() - { - // Arrange - int? value = 42; - - // Act - var option = value.ToOption(); - - // Assert - Assert.That(option.IsSome, Is.True); - Assert.That(option.Value, Is.EqualTo(42)); - } - - /// - /// 测试值类型可空转换 - 验证无值的可空值类型转换为None - /// - [Test] - public void NullableExtensions_ValueType_ToOption_Should_Create_None_For_NoValue() - { - // Arrange - int? value = null; - - // Act - var option = value.ToOption(); - - // Assert - Assert.That(option.IsNone, Is.True); - } -} \ No newline at end of file diff --git a/GFramework.Core.Tests/functional/types/OptionExtensionsTests.cs b/GFramework.Core.Tests/functional/types/OptionExtensionsTests.cs deleted file mode 100644 index 5f1dd2b..0000000 --- a/GFramework.Core.Tests/functional/types/OptionExtensionsTests.cs +++ /dev/null @@ -1,181 +0,0 @@ -using GFramework.Core.functional.types; -using NUnit.Framework; - -namespace GFramework.Core.Tests.functional.types; - -/// -/// OptionExtensions扩展方法测试类,用于验证Option类型的功能扩展方法 -/// 包括映射、绑定、过滤和匹配操作等功能的测试 -/// -[TestFixture] -public class OptionExtensionsTests -{ - /// - /// 测试Map方法 - 验证Some值能正确映射 - /// - [Test] - public void Option_Map_Should_Transform_Some_Value() - { - // Arrange - var option = Option.Some("hello"); - - // Act - var result = option.Map(s => s.Length); - - // Assert - Assert.That(result.IsSome, Is.True); - Assert.That(result.Value, Is.EqualTo(5)); - } - - /// - /// 测试Map方法 - 验证None映射后仍为None - /// - [Test] - public void Option_Map_Should_Return_None_For_None() - { - // Arrange - var option = Option.None(); - - // Act - var result = option.Map(s => s.Length); - - // Assert - Assert.That(result.IsNone, Is.True); - } - - /// - /// 测试Bind方法 - 验证Some值能正确绑定到另一个Option - /// - [Test] - public void Option_Bind_Should_Transform_Some_To_Another_Option() - { - // Arrange - var option = Option.Some("hello"); - - // Act - var result = option.Bind(s => s.Length > 3 ? Option.Some(s.Length) : Option.None()); - - // Assert - Assert.That(result.IsSome, Is.True); - Assert.That(result.Value, Is.EqualTo(5)); - } - - /// - /// 测试Bind方法 - 验证None绑定后仍为None - /// - [Test] - public void Option_Bind_Should_Return_None_For_None() - { - // Arrange - var option = Option.None(); - - // Act - var result = option.Bind(s => Option.Some(s.Length)); - - // Assert - Assert.That(result.IsNone, Is.True); - } - - /// - /// 测试Bind方法 - 验证Some值绑定到None的情况 - /// - [Test] - public void Option_Bind_Should_Return_None_When_Binder_Returns_None() - { - // Arrange - var option = Option.Some("hi"); // 长度小于3 - - // Act - var result = option.Bind(s => s.Length > 3 ? Option.Some(s.Length) : Option.None()); - - // Assert - Assert.That(result.IsNone, Is.True); - } - - /// - /// 测试Filter方法 - 验证满足条件的Some值保留 - /// - [Test] - public void Option_Filter_Should_Keep_Some_When_Predicate_Matches() - { - // Arrange - var option = Option.Some("hello"); - - // Act - var result = option.Filter(s => s.Length > 3); - - // Assert - Assert.That(result.IsSome, Is.True); - Assert.That(result.Value, Is.EqualTo("hello")); - } - - /// - /// 测试Filter方法 - 验证不满足条件的Some值变为None - /// - [Test] - public void Option_Filter_Should_Return_None_When_Predicate_Does_Not_Match() - { - // Arrange - var option = Option.Some("hi"); - - // Act - var result = option.Filter(s => s.Length > 3); - - // Assert - Assert.That(result.IsNone, Is.True); - } - - /// - /// 测试Filter方法 - 验证None过滤后仍为None - /// - [Test] - public void Option_Filter_Should_Return_None_For_None() - { - // Arrange - var option = Option.None(); - - // Act - var result = option.Filter(s => s.Length > 3); - - // Assert - Assert.That(result.IsNone, Is.True); - } - - /// - /// 测试Match方法 - 验证Some值执行some分支 - /// - [Test] - public void Option_Match_Should_Execute_Some_Branch_For_Some() - { - // Arrange - var option = Option.Some("hello"); - - // Act - var result = option.Match( - some: s => $"Value: {s}", - none: () => "No value" - ); - - // Assert - Assert.That(result, Is.EqualTo("Value: hello")); - } - - /// - /// 测试Match方法 - 验证None值执行none分支 - /// - [Test] - public void Option_Match_Should_Execute_None_Branch_For_None() - { - // Arrange - var option = Option.None(); - - // Act - var result = option.Match( - some: s => $"Value: {s}", - none: () => "No value" - ); - - // Assert - Assert.That(result, Is.EqualTo("No value")); - } -} \ No newline at end of file diff --git a/GFramework.Core.Tests/functional/types/OptionTests.cs b/GFramework.Core.Tests/functional/types/OptionTests.cs deleted file mode 100644 index bbb59ba..0000000 --- a/GFramework.Core.Tests/functional/types/OptionTests.cs +++ /dev/null @@ -1,70 +0,0 @@ -using GFramework.Core.functional.types; -using NUnit.Framework; - -namespace GFramework.Core.Tests.functional.types; - -/// -/// Option类型测试类,用于验证Option类型的基本功能 -/// 包括创建Some和None实例、值访问等功能的测试 -/// -[TestFixture] -public class OptionTests -{ - /// - /// 测试创建Some实例 - 验证非null值能正确创建Some - /// - [Test] - public void Option_Some_Should_Create_WithValue() - { - // Arrange - var value = "Hello"; - - // Act - var option = Option.Some(value); - - // Assert - Assert.That(option.IsSome, Is.True); - Assert.That(option.IsNone, Is.False); - Assert.That(option.Value, Is.EqualTo(value)); - } - - /// - /// 测试创建Some实例 - 验证null值时抛出异常 - /// - [Test] - public void Option_Some_Should_Throw_When_Value_Is_Null() - { - // Act & Assert - Assert.Throws(() => Option.Some(null!)); - } - - /// - /// 测试创建None实例 - 验证能正确创建None - /// - [Test] - public void Option_None_Should_Create_Empty_Instance() - { - // Act - var option = Option.None(); - - // Assert - Assert.That(option.IsNone, Is.True); - Assert.That(option.IsSome, Is.False); - } - - /// - /// 测试访问None的值 - 验证抛出异常 - /// - [Test] - public void Option_None_Value_Access_Should_Throw_Exception() - { - // Arrange - var option = Option.None(); - - // Act & Assert - Assert.Throws(() => - { - var _ = option.Value; - }); - } -} \ No newline at end of file diff --git a/GFramework.Core.Tests/functional/types/OptionValueExtensionsTests.cs b/GFramework.Core.Tests/functional/types/OptionValueExtensionsTests.cs deleted file mode 100644 index 653a64e..0000000 --- a/GFramework.Core.Tests/functional/types/OptionValueExtensionsTests.cs +++ /dev/null @@ -1,141 +0,0 @@ -using GFramework.Core.functional.types; -using NUnit.Framework; - -namespace GFramework.Core.Tests.functional.types; - -/// -/// OptionValueExtensions扩展方法测试类,用于验证Option类型值的操作扩展方法 -/// 包括获取默认值、备选Option等功能的测试 -/// -[TestFixture] -public class OptionValueExtensionsTests -{ - /// - /// 测试GetOrElse方法 - 验证Some值直接返回其值 - /// - [Test] - public void OptionValueExtensions_GetOrElse_Should_Return_Value_For_Some() - { - // Arrange - var option = Option.Some("actual value"); - - // Act - var result = option.GetOrElse("default value"); - - // Assert - Assert.That(result, Is.EqualTo("actual value")); - } - - /// - /// 测试GetOrElse方法 - 验证None值返回默认值 - /// - [Test] - public void OptionValueExtensions_GetOrElse_Should_Return_Default_For_None() - { - // Arrange - var option = Option.None(); - - // Act - var result = option.GetOrElse("default value"); - - // Assert - Assert.That(result, Is.EqualTo("default value")); - } - - /// - /// 测试GetOrElse方法(工厂函数) - 验证Some值直接返回其值(不调用工厂) - /// - [Test] - public void OptionValueExtensions_GetOrElse_With_Factory_Should_Return_Value_For_Some() - { - // Arrange - var option = Option.Some("actual value"); - var factoryCalled = false; - - // Act - var result = option.GetOrElse(() => - { - factoryCalled = true; - return "factory value"; - }); - - // Assert - Assert.That(result, Is.EqualTo("actual value")); - Assert.That(factoryCalled, Is.False); - } - - /// - /// 测试GetOrElse方法(工厂函数) - 验证None值调用工厂函数 - /// - [Test] - public void OptionValueExtensions_GetOrElse_With_Factory_Should_Call_Factory_For_None() - { - // Arrange - var option = Option.None(); - var factoryCalled = false; - - // Act - var result = option.GetOrElse(() => - { - factoryCalled = true; - return "factory value"; - }); - - // Assert - Assert.That(result, Is.EqualTo("factory value")); - Assert.That(factoryCalled, Is.True); - } - - /// - /// 测试OrElse方法 - 验证Some值返回自身 - /// - [Test] - public void OptionValueExtensions_OrElse_Should_Return_Self_For_Some() - { - // Arrange - var option = Option.Some("primary value"); - var fallback = Option.Some("fallback value"); - - // Act - var result = option.OrElse(fallback); - - // Assert - Assert.That(result.IsSome, Is.True); - Assert.That(result.Value, Is.EqualTo("primary value")); - } - - /// - /// 测试OrElse方法 - 验证None值返回备选Option - /// - [Test] - public void OptionValueExtensions_OrElse_Should_Return_Fallback_For_None() - { - // Arrange - var option = Option.None(); - var fallback = Option.Some("fallback value"); - - // Act - var result = option.OrElse(fallback); - - // Assert - Assert.That(result.IsSome, Is.True); - Assert.That(result.Value, Is.EqualTo("fallback value")); - } - - /// - /// 测试OrElse方法 - 验证None值返回备选None - /// - [Test] - public void OptionValueExtensions_OrElse_Should_Return_Fallback_None_For_None() - { - // Arrange - var option = Option.None(); - var fallback = Option.None(); - - // Act - var result = option.OrElse(fallback); - - // Assert - Assert.That(result.IsNone, Is.True); - } -} \ No newline at end of file diff --git a/GFramework.Core.Tests/functional/types/ResultExtensionsTests.cs b/GFramework.Core.Tests/functional/types/ResultExtensionsTests.cs deleted file mode 100644 index 4c867b6..0000000 --- a/GFramework.Core.Tests/functional/types/ResultExtensionsTests.cs +++ /dev/null @@ -1,171 +0,0 @@ -using GFramework.Core.functional.types; -using NUnit.Framework; - -namespace GFramework.Core.Tests.functional.types; - -/// -/// ResultExtensions扩展方法测试类,用于验证Result类型的功能扩展方法 -/// 包括映射、绑定、错误映射和匹配操作等功能的测试 -/// -[TestFixture] -public class ResultExtensionsTests -{ - /// - /// 测试Map方法 - 验证Success值能正确映射 - /// - [Test] - public void Result_Map_Should_Transform_Success_Value() - { - // Arrange - var result = Result.Success("hello"); - - // Act - var mappedResult = result.Map(s => s.Length); - - // Assert - Assert.That(mappedResult.IsSuccess, Is.True); - Assert.That(mappedResult.SuccessValue, Is.EqualTo(5)); - } - - /// - /// 测试Map方法 - 验证Failure映射后仍保持Failure状态 - /// - [Test] - public void Result_Map_Should_Keep_Failure_For_Failure() - { - // Arrange - var result = Result.Failure("error occurred"); - - // Act - var mappedResult = result.Map(s => s.Length); - - // Assert - Assert.That(mappedResult.IsFailure, Is.True); - Assert.That(mappedResult.ErrorValue, Is.EqualTo("error occurred")); - } - - /// - /// 测试Bind方法 - 验证Success值能正确绑定到另一个Result - /// - [Test] - public void Result_Bind_Should_Transform_Success_To_Another_Result() - { - // Arrange - var result = Result.Success("hello"); - - // Act - var boundResult = result.Bind(s => - s.Length > 3 ? Result.Success(s.Length) : Result.Failure("Length too small")); - - // Assert - Assert.That(boundResult.IsSuccess, Is.True); - Assert.That(boundResult.SuccessValue, Is.EqualTo(5)); - } - - /// - /// 测试Bind方法 - 验证Failure绑定后仍保持Failure状态 - /// - [Test] - public void Result_Bind_Should_Keep_Failure_For_Failure() - { - // Arrange - var result = Result.Failure("initial error"); - - // Act - var boundResult = result.Bind(s => Result.Success(s.Length)); - - // Assert - Assert.That(boundResult.IsFailure, Is.True); - Assert.That(boundResult.ErrorValue, Is.EqualTo("initial error")); - } - - /// - /// 测试Bind方法 - 验证Success值绑定到Failure的情况 - /// - [Test] - public void Result_Bind_Should_Allow_Transition_To_Failure() - { - // Arrange - var result = Result.Success("hi"); // 长度小于3 - - // Act - var boundResult = result.Bind(s => - s.Length > 3 ? Result.Success(s.Length) : Result.Failure("Length too small")); - - // Assert - Assert.That(boundResult.IsFailure, Is.True); - Assert.That(boundResult.ErrorValue, Is.EqualTo("Length too small")); - } - - /// - /// 测试MapError方法 - 验证Failure错误值能正确映射 - /// - [Test] - public void Result_MapError_Should_Transform_Failure_Error() - { - // Arrange - var result = Result.Failure("original error"); - - // Act - var mappedErrorResult = result.MapError(err => $"Mapped: {err}"); - - // Assert - Assert.That(mappedErrorResult.IsFailure, Is.True); - Assert.That(mappedErrorResult.ErrorValue, Is.EqualTo("Mapped: original error")); - } - - /// - /// 测试MapError方法 - 验证Success映射错误后仍保持Success状态 - /// - [Test] - public void Result_MapError_Should_Keep_Success_For_Success() - { - // Arrange - var result = Result.Success("success data"); - - // Act - var mappedErrorResult = result.MapError(err => $"Mapped: {err}"); - - // Assert - Assert.That(mappedErrorResult.IsSuccess, Is.True); - Assert.That(mappedErrorResult.SuccessValue, Is.EqualTo("success data")); - } - - /// - /// 测试Match方法 - 验证Success值执行onSuccess分支 - /// - [Test] - public void Result_Match_Should_Execute_OnSuccess_Branch_For_Success() - { - // Arrange - var result = Result.Success("success data"); - - // Act - var matchedResult = result.Match( - onSuccess: data => $"Success: {data}", - onFailure: error => $"Error: {error}" - ); - - // Assert - Assert.That(matchedResult, Is.EqualTo("Success: success data")); - } - - /// - /// 测试Match方法 - 验证Failure值执行onFailure分支 - /// - [Test] - public void Result_Match_Should_Execute_OnFailure_Branch_For_Failure() - { - // Arrange - var result = Result.Failure("something failed"); - - // Act - var matchedResult = result.Match( - onSuccess: data => $"Success: {data}", - onFailure: error => $"Error: {error}" - ); - - // Assert - Assert.That(matchedResult, Is.EqualTo("Error: something failed")); - } -} \ No newline at end of file diff --git a/GFramework.Core.Tests/functional/types/ResultTests.cs b/GFramework.Core.Tests/functional/types/ResultTests.cs deleted file mode 100644 index 0ee9947..0000000 --- a/GFramework.Core.Tests/functional/types/ResultTests.cs +++ /dev/null @@ -1,108 +0,0 @@ -using GFramework.Core.functional.types; -using NUnit.Framework; - -namespace GFramework.Core.Tests.functional.types; - -/// -/// Result类型测试类,用于验证Result类型的基本功能 -/// 包括创建Success和Failure实例、值访问等功能的测试 -/// -[TestFixture] -public class ResultTests -{ - /// - /// 测试创建Success实例 - 验证能正确创建成功结果 - /// - [Test] - public void Result_Success_Should_Create_With_Value() - { - // Arrange - var value = "Success data"; - - // Act - var result = Result.Success(value); - - // Assert - Assert.That(result.IsSuccess, Is.True); - Assert.That(result.IsFailure, Is.False); - Assert.That(result.SuccessValue, Is.EqualTo(value)); - } - - /// - /// 测试访问Success值 - 验证能正确获取成功值 - /// - [Test] - public void Result_Success_Value_Access_Should_Work() - { - // Arrange - var result = Result.Success("test"); - - // Act & Assert - Assert.That(result.IsSuccess, Is.True); - Assert.That(result.SuccessValue, Is.EqualTo("test")); - } - - /// - /// 测试访问Success的错误值 - 验证在成功状态下访问错误值抛出异常 - /// - [Test] - public void Result_Success_Error_Access_Should_Throw_Exception() - { - // Arrange - var result = Result.Success("success"); - - // Act & Assert - Assert.Throws(() => - { - var _ = result.ErrorValue; - }); - } - - /// - /// 测试创建Failure实例 - 验证能正确创建失败结果 - /// - [Test] - public void Result_Failure_Should_Create_With_Error() - { - // Arrange - var error = "Something went wrong"; - - // Act - var result = Result.Failure(error); - - // Assert - Assert.That(result.IsFailure, Is.True); - Assert.That(result.IsSuccess, Is.False); - Assert.That(result.ErrorValue, Is.EqualTo(error)); - } - - /// - /// 测试访问Failure值 - 验证能正确获取错误值 - /// - [Test] - public void Result_Failure_Value_Access_Should_Work() - { - // Arrange - var result = Result.Failure("error"); - - // Act & Assert - Assert.That(result.IsFailure, Is.True); - Assert.That(result.ErrorValue, Is.EqualTo("error")); - } - - /// - /// 测试访问Failure的成功值 - 验证在失败状态下访问成功值抛出异常 - /// - [Test] - public void Result_Failure_Success_Access_Should_Throw_Exception() - { - // Arrange - var result = Result.Failure("error"); - - // Act & Assert - Assert.Throws(() => - { - var _ = result.SuccessValue; - }); - } -} \ No newline at end of file diff --git a/GFramework.Core.Tests/functional/types/TypeExtensionsTests.cs b/GFramework.Core.Tests/functional/types/TypeExtensionsTests.cs deleted file mode 100644 index 2164ab9..0000000 --- a/GFramework.Core.Tests/functional/types/TypeExtensionsTests.cs +++ /dev/null @@ -1,69 +0,0 @@ -using GFramework.Core.extensions; -using GFramework.Core.functional.types; -using NUnit.Framework; - -namespace GFramework.Core.Tests.functional.types; - -/// -/// TypeExtensions扩展方法测试类,用于验证类型转换相关扩展方法的正确性 -/// 包括安全类型转换和强制类型转换功能的测试 -/// -[TestFixture] -public class TypeExtensionsTests -{ - #region As Tests - - /// - /// 测试As方法 - 验证安全类型转换功能 - /// - [Test] - public void As_Should_Perform_Safe_Type_Cast() - { - // Arrange - object obj = "Hello"; - - // Act - var result = obj.As(); - - // Assert - Assert.That(result, Is.EqualTo("Hello")); - } - - /// - /// 测试As方法 - 验证不兼容类型转换返回null - /// - [Test] - public void As_Should_Return_Null_For_Incompatible_Types() - { - // Arrange - object obj = 42; - - // Act - var result = obj.As(); - - // Assert - Assert.That(result, Is.Null); - } - - #endregion - - #region Cast Tests - - /// - /// 测试Cast方法 - 验证强制类型转换功能 - /// - [Test] - public void Cast_Should_Perform_Forced_Type_Cast() - { - // Arrange - object obj = "Hello"; - - // Act - var result = obj.Cast(); - - // Assert - Assert.That(result, Is.EqualTo("Hello")); - } - - #endregion -} \ No newline at end of file diff --git a/GFramework.Core/GFramework.Core.csproj b/GFramework.Core/GFramework.Core.csproj index 203f539..a4d0adf 100644 --- a/GFramework.Core/GFramework.Core.csproj +++ b/GFramework.Core/GFramework.Core.csproj @@ -9,4 +9,7 @@ + + + diff --git a/GFramework.Core/GlobalUsings.cs b/GFramework.Core/GlobalUsings.cs index 4d27181..05d852c 100644 --- a/GFramework.Core/GlobalUsings.cs +++ b/GFramework.Core/GlobalUsings.cs @@ -15,4 +15,7 @@ global using System; global using System.Collections.Generic; global using System.Linq; global using System.Threading; -global using System.Threading.Tasks; \ No newline at end of file +global using System.Threading.Tasks; +global using LanguageExt.Common; +global using LanguageExt.Effects; +global using LanguageExt.Pretty; \ No newline at end of file diff --git a/GFramework.Core/coroutine/CoroutineScheduler.cs b/GFramework.Core/coroutine/CoroutineScheduler.cs index 263ad1e..664d6a9 100644 --- a/GFramework.Core/coroutine/CoroutineScheduler.cs +++ b/GFramework.Core/coroutine/CoroutineScheduler.cs @@ -235,7 +235,6 @@ public sealed class CoroutineScheduler( public int Clear() { var count = ActiveCoroutineCount; - Array.Clear(_slots); _metadata.Clear(); _tagged.Clear(); diff --git a/GFramework.Core/functional/README.md b/GFramework.Core/functional/README.md deleted file mode 100644 index 4febcc2..0000000 --- a/GFramework.Core/functional/README.md +++ /dev/null @@ -1,421 +0,0 @@ -# Functional Extensions - 函数式编程扩展方法 - -提供了一系列用于函数式编程的扩展方法,已按功能拆分为多个类别。 - -## 功能概览 - -这些扩展方法实现了函数式编程的核心概念,包括管道操作、函数组合、集合操作、控制流、类型转换等功能,使C#代码更加简洁和函数式。 - -## 模块分类 - -### 1. Pipe Extensions - 管道和函数组合操作 -位于 `GFramework.Core.functional.pipe` 命名空间,提供管道和函数组合操作。 - -#### 方法列表及用法: -- **Pipe** - 把值送进函数 -```csharp -// 将值传入函数进行处理 -var result = 5.Pipe(x => x * 2); // 结果为 10 -``` - -- **Then** - 函数组合(f1.Then(f2)) -```csharp -// 组合两个函数,先执行first再执行second -Func addTwo = x => x + 2; -Func multiplyByThree = x => x * 3; -var composed = addTwo.Then(multiplyByThree); // 先+2再*3 -var result = composed(5); // (5+2)*3 = 21 -``` - -- **After** - 反向函数组合 -```csharp -// 与Then相反,以不同的顺序组合函数 -Func multiplyByThree = x => x * 3; -Func addTwo = x => x + 2; -var composed = multiplyByThree.After(addTwo); // 先+2再*3 -var result = composed(5); // (5+2)*3 = 21 -``` - -- **Tap** - 执行副作用操作但返回原值 -```csharp -// 执行副作用操作但返回原值,常用于调试或日志记录 -var value = 42.Tap(Console.WriteLine); // 输出42,但value仍为42 -``` - -- **Apply** - 将函数应用于值 -```csharp -// 将参数应用于函数 -Func multiplyByTwo = x => x * 2; -var result = multiplyByTwo.Apply(5); // 10 -``` - -- **Also** - 执行操作并返回原值 -```csharp -// 执行操作并返回原值 -var value = 42.Also(Console.WriteLine); // 输出42,返回42 -``` - -- **Let** - 将值转换为另一个值 -```csharp -// 转换值 -var result = 5.Let(x => x * 2); // 10 -``` - -### 2. Collections Extensions - 集合操作 -位于 `GFramework.Core.functional.collections` 命名空间,提供对集合的函数式操作。 - -#### 方法列表及用法: -- **Map** - 映射操作 -```csharp -// 对集合中的每个元素应用函数 -var numbers = new[] {1, 2, 3, 4}; -var squared = numbers.Map(x => x * x); // {1, 4, 9, 16} -``` - -- **Filter** - 过滤操作 -```csharp -// 过滤集合中的元素 -var numbers = new[] {1, 2, 3, 4, 5, 6}; -var evens = numbers.Filter(x => x % 2 == 0); // {2, 4, 6} -``` - -- **Reduce** - 归约操作 -```csharp -// 将集合归约为单个值 -var numbers = new[] {1, 2, 3, 4}; -var sum = numbers.Reduce(0, (acc, x) => acc + x); // 10 -``` - -### 3. Control Extensions - 控制流操作 -位于 `GFramework.Core.functional.control` 命名空间,提供函数式风格的控制结构。 - -#### 方法列表及用法: -- **Match** - 模式匹配 -```csharp -// 基于条件的模式匹配 -var result = 5.Match( - (x => x < 0, _ => "负数"), - (x => x > 0, _ => "正数"), - (x => x == 0, _ => "零") -); // "正数" -``` - -- **MatchOrDefault** - 带默认值的模式匹配 -```csharp -// 模式匹配,无匹配时返回默认值 -var result = 0.MatchOrDefault("未知数字", - (x => x < 0, _ => "负数"), - (x => x > 0, _ => "正数") -); // "未知数字" -``` - -- **If / IfElse** - 条件执行 -```csharp -// 条件执行操作 -var result = 5.If(x => x > 0, x => x * 2); // 10 (因为5>0,所以乘以2) -var result2 = 5.IfElse( - x => x > 10, - x => x * 2, // 条件为真时执行 - x => x + 1 // 条件为假时执行 -); // 6 (因为5不大于10,所以+1) -``` - -- **TakeIf / TakeUnless** - 条件取值 -```csharp -// 条件为真时返回值,否则返回null -string str = "Hello"; -var result1 = str.TakeIf(s => s.Length > 3); // "Hello" -var result2 = str.TakeIf(s => s.Length < 3); // null - -// 条件为假时返回值,否则返回null -var result3 = str.TakeUnless(s => s.Length > 10); // "Hello" (因为长度不大于10) -var result4 = str.TakeUnless(s => s.Length > 3); // null (因为长度大于3) -``` - -### 4. Function Extensions - 函数式操作 -位于 `GFramework.Core.functional.functions` 命名空间,提供柯里化、偏函数应用等高级函数式特性。 - -#### 方法列表及用法: -- **Curry** - 柯里化 -```csharp -// 将多参数函数转换为链式单参数函数 -Func add = (x, y) => x + y; -var curriedAdd = add.Curry(); // 返回 Func> -var addFive = curriedAdd(5); // 返回 Func -var result = addFive(3); // 8 -``` - -- **Uncurry** - 取消柯里化 -```csharp -// 将柯里化函数转换回多参数函数 -var curriedAdd = ((Func)((x, y) => x + y)).Curry(); -var uncurriedAdd = curriedAdd.Uncurry(); // 返回 Func -var result = uncurriedAdd(5, 3); // 8 -``` - -- **Partial** - 部分应用 -```csharp -// 固定函数的部分参数 -Func multiply = (x, y) => x * y; -var double = multiply.Partial(2); // 固定第一个参数为2 -var result = double(5); // 10 -``` - -- **Repeat** - 重复执行 -```csharp -// 重复执行函数n次 -var result = 2.Repeat(3, x => x * 2); // 2 -> 4 -> 8 -> 16 -``` - -- **Try** - 安全执行 -```csharp -// 安全执行可能抛出异常的函数 -var (success, result, error) = 10.Try(x => 100 / x); // 成功,result为10 -var (success2, result2, error2) = 0.Try(x => 100 / x); // 失败,success2为false -``` - -- **Memoize** - 缓存结果 -```csharp -// 缓存函数结果以提高性能 -Func expensiveFunction = x => -{ - // 模拟耗时操作 - System.Threading.Thread.Sleep(1000); - return x * x; -}; -var memoized = expensiveFunction.Memoize(); -var result1 = memoized(5); // 首次调用需要1秒 -var result2 = memoized(5); // 立即返回,使用缓存结果 -``` - -### 5. Type Extensions - 类型转换 -位于 `GFramework.Core.functional.types` 命名空间,提供类型转换相关的扩展方法。 - -#### 方法列表及用法: -- **As** - 安全类型转换 -```csharp -// 安全类型转换,失败时返回null -object obj = "Hello"; -var str = obj.As(); // "Hello" -var incompatible = obj.As(); // null -``` - -- **Cast** - 强制类型转换 -```csharp -// 强制类型转换,失败时抛出异常 -object obj = "Hello"; -var str = obj.Cast(); // "Hello" -``` - -### 6. Option Type - 可选值类型 - -位于 `GFramework.Core.functional.types` 命名空间,提供表示可能存在或不存在的值的类型。 - -#### 核心类型及用法: - -- **Option<T>** - 表示可能包含值或不包含值的类型 - -```csharp -// 创建包含值的Option -var someValue = Option<string>.Some("Hello"); -Console.WriteLine(someValue.IsSome); // True -Console.WriteLine(someValue.Value); // "Hello" - -// 创建空的Option -var noValue = Option<string>.None(); -Console.WriteLine(noValue.IsNone); // True -``` - -#### Option扩展方法: - -- **Map** - 对Option中的值进行映射转换 - -```csharp -var someValue = Option<string>.Some("hello"); -var lengthOption = someValue.Map(s => s.Length); // Some(5) - -var noneValue = Option<string>.None(); -var noneLength = noneValue.Map(s => s.Length); // None -``` - -- **Bind** - 将Option中的值转换为另一个Option - -```csharp -var someValue = Option<string>.Some("hello"); -var result = someValue.Bind(s => s.Length > 3 ? Option<int>.Some(s.Length) : Option<int>.None()); // Some(5) - -var shortValue = Option<string>.Some("hi"); -var result2 = shortValue.Bind(s => s.Length > 3 ? Option<int>.Some(s.Length) : Option<int>.None()); // None -``` - -- **Filter** - 根据条件过滤Option中的值 - -```csharp -var someValue = Option<string>.Some("hello"); -var filtered = someValue.Filter(s => s.Length > 3); // Some("hello") -var filtered2 = someValue.Filter(s => s.Length > 10); // None -``` - -- **Match** - 模式匹配Option的状态 - -```csharp -var someValue = Option<string>.Some("hello"); -var result = someValue.Match( - some: s => $"Value: {s}", - none: () => "No value" -); // "Value: hello" - -var noneValue = Option<string>.None(); -var result2 = noneValue.Match( - some: s => $"Value: {s}", - none: () => "No value" -); // "No value" -``` - -- **GetOrElse** - 获取值或返回默认值 - -```csharp -var someValue = Option<string>.Some("hello"); -var value1 = someValue.GetOrElse("default"); // "hello" - -var noneValue = Option<string>.None(); -var value2 = noneValue.GetOrElse("default"); // "default" -``` - -- **OrElse** - 当前Option为空时返回备选Option - -```csharp -var someValue = Option<string>.Some("primary"); -var result1 = someValue.OrElse(Option<string>.Some("fallback")); // Some("primary") - -var noneValue = Option<string>.None(); -var result2 = noneValue.OrElse(Option<string>.Some("fallback")); // Some("fallback") -``` - -### 7. Result Type - 结果类型 - -位于 `GFramework.Core.functional.types` 命名空间,提供表示成功或失败结果的类型。 - -#### 核心类型及用法: - -- **Result<TSuccess, TError>** - 表示可能成功或失败的计算结果 - -```csharp -// 创建成功的结果 -var successResult = Result<string, string>.Success("Operation successful"); -Console.WriteLine(successResult.IsSuccess); // True -Console.WriteLine(successResult.SuccessValue); // "Operation successful" - -// 创建失败的结果 -var failureResult = Result<string, string>.Failure("Operation failed"); -Console.WriteLine(failureResult.IsFailure); // True -Console.WriteLine(failureResult.ErrorValue); // "Operation failed" -``` - -#### Result扩展方法: - -- **Map** - 对成功值进行映射转换 - -```csharp -var successResult = Result<string, string>.Success("hello"); -var lengthResult = successResult.Map(s => s.Length); // Success(5) - -var failureResult = Result<string, string>.Failure("error"); -var lengthResult2 = failureResult.Map(s => s.Length); // Failure("error") -``` - -- **Bind** - 将成功值转换为另一个Result - -```csharp -var successResult = Result<string, string>.Success("hello"); -var result = successResult.Bind(s => - s.Length > 3 ? - Result<int, string>.Success(s.Length) : - Result<int, string>.Failure("Length too small")); -// Result<int, string>.Success(5) -``` - -- **MapError** - 对错误值进行映射转换 - -```csharp -var failureResult = Result<string, string>.Failure("original error"); -var mappedErrorResult = failureResult.MapError(err => $"Mapped: {err}"); -// Result<string, string>.Failure("Mapped: original error") -``` - -- **Match** - 模式匹配Result的状态 - -```csharp -var successResult = Result<string, string>.Success("data"); -var result = successResult.Match( - onSuccess: data => $"Success: {data}", - onFailure: error => $"Error: {error}" -); // "Success: data" - -var failureResult = Result<string, string>.Failure("error"); -var result2 = failureResult.Match( - onSuccess: data => $"Success: {data}", - onFailure: error => $"Error: {error}" -); // "Error: error" -``` - -### 8. Nullable Extensions - 可空类型扩展 - -位于 `GFramework.Core.functional.types` 命名空间,提供将可空类型转换为Option类型的方法。 - -#### 方法列表及用法: - -- **ToOption** - 将可空类型转换为Option - -```csharp -// 引用类型可空转换 -string? stringValue = "Hello"; -var someOption = stringValue.ToOption(); // Some("Hello") - -string? nullString = null; -var noneOption = nullString.ToOption(); // None - -// 值类型可空转换 -int? intValue = 42; -var someIntOption = intValue.ToOption(); // Some(42) - -int? nullInt = null; -var noneIntOption = nullInt.ToOption(); // None -``` - -## 使用示例 - -### 链式操作 -```csharp -var result = new[] {1, 2, 3, 4, 5} - .Filter(x => x % 2 == 0) // 过滤偶数: {2, 4} - .Map(x => x * x) // 平方: {4, 16} - .Reduce(0, (sum, x) => sum + x); // 求和: 20 -``` - -### 函数组合 -```csharp -// 创建复合函数 -Func addTwo = x => x + 2; -Func square = x => x * x; -Func subtractOne = x => x - 1; - -// 组合多个函数 -var complexOperation = addTwo.Then(square).Then(subtractOne); -var result = complexOperation(3); // ((3+2)^2)-1 = 24 -``` - -## 注意事项 - -- 部分方法(如Memoize)对泛型参数有约束(例如`where TSource : notnull`) -- Try方法返回元组,便于处理可能发生的异常 -- 柯里化和部分应用有助于创建更灵活的函数 -- 链式操作可以提高代码可读性,但要注意性能影响 - -## 适用场景 - -- 数据转换和处理管道 -- 函数组合和复用 -- 避免中间变量的创建 -- 提高代码的声明式风格 -- 创建可重用的功能组件 \ No newline at end of file diff --git a/GFramework.Core/functional/collections/EnumerableExtensions.cs b/GFramework.Core/functional/collections/EnumerableExtensions.cs deleted file mode 100644 index 1fb2e09..0000000 --- a/GFramework.Core/functional/collections/EnumerableExtensions.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2025 GeWuYou -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -namespace GFramework.Core.functional.collections; - -/// -/// 提供集合的函数式编程扩展方法 -/// -public static class EnumerableExtensions -{ - /// - /// Map:对集合中的每个元素应用函数 - /// - /// 源集合元素的类型 - /// 映射后集合元素的类型 - /// 要映射的源集合 - /// 用于转换元素的函数 - /// 映射后的元素序列 - public static IEnumerable Map( - this IEnumerable source, - Func selector) - => source.Select(selector); - - /// - /// Filter:过滤集合 - /// - /// 集合元素的类型 - /// 要过滤的源集合 - /// 用于确定是否包含元素的条件函数 - /// 满足条件的元素序列 - public static IEnumerable Filter( - this IEnumerable source, - Func predicate) - => source.Where(predicate); - - /// - /// Reduce:将集合归约为单个值 - /// - /// 集合元素的类型 - /// 归约结果的类型 - /// 要归约的源集合 - /// 初始累加值 - /// 累加器函数 - /// 归约后的最终值 - public static TResult Reduce( - this IEnumerable source, - TResult seed, - Func accumulator) - => source.Aggregate(seed, accumulator); -} diff --git a/GFramework.Core/functional/control/ControlExtensions.cs b/GFramework.Core/functional/control/ControlExtensions.cs index 92ccd76..49473a8 100644 --- a/GFramework.Core/functional/control/ControlExtensions.cs +++ b/GFramework.Core/functional/control/ControlExtensions.cs @@ -11,8 +11,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -using GFramework.Core.functional.types; - namespace GFramework.Core.functional.control; /// @@ -20,82 +18,6 @@ namespace GFramework.Core.functional.control; /// public static class ControlExtensions { - /// - /// Match:模式匹配(类似switch表达式) - /// - /// 输入值的类型 - /// 匹配结果的类型 - /// 要进行模式匹配的输入值 - /// 匹配案例数组,每个包含谓词和处理器 - /// 匹配到的处理结果 - /// 当没有匹配的案例时抛出 - public static Option Match( - this TSource value, - params (Func predicate, Func handler)[] cases) - { - foreach (var (predicate, handler) in cases) - { - if (predicate(value)) - return Option.Some(handler(value)); - } - - return Option.None(); - } - - - /// - /// MatchOrDefault:带默认值的模式匹配 - /// - /// 输入值的类型 - /// 匹配结果的类型 - /// 要进行模式匹配的输入值 - /// 当没有匹配案例时的默认返回值 - /// 匹配案例数组,每个包含谓词和处理器 - /// 匹配到的处理结果或默认值 - public static TResult MatchOrDefault( - this TSource value, - TResult defaultValue, - params (Func predicate, Func handler)[] cases) - { - foreach (var (predicate, handler) in cases) - { - if (predicate(value)) - return handler(value); - } - - return defaultValue; - } - - /// - /// If:条件执行 - /// - /// 输入值的类型 - /// 要进行条件判断的输入值 - /// 条件判断函数 - /// 条件为真时执行的转换函数 - /// 条件为真时返回转换后的值,否则返回原值 - public static TSource If( - this TSource value, - Func predicate, - Func thenFunc) - => predicate(value) ? thenFunc(value) : value; - - /// - /// IfElse:条件分支 - /// - /// 输入值的类型 - /// 要进行条件判断的输入值 - /// 条件判断函数 - /// 条件为真时执行的转换函数 - /// 条件为假时执行的转换函数 - /// 根据条件返回相应的转换结果 - public static TSource IfElse( - this TSource value, - Func predicate, - Func thenFunc, - Func elseFunc) - => predicate(value) ? thenFunc(value) : elseFunc(value); - /// /// TakeIf:条件返回值或null /// diff --git a/GFramework.Core/functional/functions/FunctionExtensions.cs b/GFramework.Core/functional/functions/FunctionExtensions.cs index dd562f5..a778363 100644 --- a/GFramework.Core/functional/functions/FunctionExtensions.cs +++ b/GFramework.Core/functional/functions/FunctionExtensions.cs @@ -20,42 +20,23 @@ namespace GFramework.Core.functional.functions; /// public static class FunctionExtensions { - #region 部分应用 - Partial + #region Repeat /// - /// Partial:部分应用函数(固定第一个参数) + /// Repeat:对值重复应用函数 n 次 /// - /// 第一个参数的类型 - /// 第二个参数的类型 - /// 函数返回结果的类型 - /// 要部分应用的二参数函数 - /// 要固定的第一个参数值 - /// 部分应用后的函数,只接受第二个参数 - public static Func Partial( - this Func func, - T1 firstArg) - => x => func(firstArg, x); - - #endregion - - #region 重复执行 - Repeat - - /// - /// Repeat:重复执行函数n次 - /// - /// 输入值的类型 - /// 初始输入值 - /// 重复执行的次数 - /// 要重复执行的函数 - /// 经过多次变换后的最终值 - public static TSource Repeat( - this TSource value, + /// + /// 当 times 小于 0 时抛出 + /// + public static T Repeat( + this T value, int times, - Func func) + Func func) { + ArgumentOutOfRangeException.ThrowIfNegative(times); + var result = value; - // 循环执行指定次数的函数调用 - for (int i = 0; i < times; i++) + for (var i = 0; i < times; i++) { result = func(result); } @@ -65,97 +46,59 @@ public static class FunctionExtensions #endregion - #region 安全执行 - Try + #region Try → Result /// - /// Try:安全执行,捕获异常 + /// Try:安全执行并返回 language-ext 的 Result /// - /// 输入值的类型 - /// 函数返回结果的类型 - /// 要传递给函数的输入值 - /// 要安全执行的函数 - /// 包含执行状态、结果和错误信息的元组 - public static (bool success, TResult? result, Exception? error) Try( + public static Result Try( this TSource value, Func func) { try { - return (true, func(value), null); + return new Result(func(value)); } catch (Exception ex) { - return (false, default, ex); + return new Result(ex); } } #endregion - #region 缓存 - Memoize + #region Memoize (Unbounded / Unsafe) /// - /// Memoize:缓存函数结果(线程安全版本) + /// MemoizeUnbounded: + /// 对函数结果进行无界缓存(线程安全) + /// + /// ⚠ 注意: + /// - 缓存永不释放 + /// - TSource 必须具有稳定的 Equals / GetHashCode + /// - 仅适用于纯函数 /// - /// 函数输入参数的类型 - /// 函数返回结果的类型 - /// 要缓存结果的函数 - /// 带有缓存功能的包装函数 - /// - /// 此版本使用ConcurrentDictionary确保线程安全。 - /// GetOrAdd是原子操作,可以安全地在多线程环境中使用。 - /// - public static Func Memoize( + public static Func MemoizeUnbounded( this Func func) where TSource : notnull { var cache = new ConcurrentDictionary(); - return x => cache.GetOrAdd(x, func); + return key => cache.GetOrAdd(key, func); } #endregion - #region 映射 - Map + #region Partial (Advanced) /// - /// Map:对单个对象应用函数 + /// Partial:部分应用(二参数函数固定第一个参数) + /// + /// ⚠ 偏函数应用属于高级用法,不建议在业务代码滥用 /// - /// 源对象类型 - /// 映射后的类型 - /// 要映射的源对象 - /// 转换函数 - /// 映射后的对象 - public static TResult Map( - this TSource source, - Func selector) - => selector(source); - - #endregion - - #region 柯里化 - Curry/Uncurry - - /// - /// Curry:将二参数函数转换为柯里化形式 - /// - /// 第一个参数的类型 - /// 第二个参数的类型 - /// 函数返回结果的类型 - /// 要柯里化的二参数函数 - /// 柯里化后的函数,接受一个参数并返回另一个函数 - public static Func> Curry( - this Func func) - => x => y => func(x, y); - - /// - /// Uncurry:将柯里化函数转换回二参数函数 - /// - /// 第一个参数的类型 - /// 第二个参数的类型 - /// 函数返回结果的类型 - /// 要取消柯里化的函数 - /// 恢复为二参数的函数 - public static Func Uncurry( - this Func> func) - => (x, y) => func(x)(y); + public static Func Partial( + this Func func, + T1 firstArg) + => second => func(firstArg, second); #endregion } \ No newline at end of file diff --git a/GFramework.Core/functional/pipe/PipeExtensions.cs b/GFramework.Core/functional/pipe/PipeExtensions.cs index b636f33..5dab5d4 100644 --- a/GFramework.Core/functional/pipe/PipeExtensions.cs +++ b/GFramework.Core/functional/pipe/PipeExtensions.cs @@ -19,71 +19,16 @@ namespace GFramework.Core.functional.pipe; public static class PipeExtensions { /// - /// Pipe:把值送进函数(value.Pipe(func)) + /// Also: + /// 对值执行副作用操作并返回原值 + /// + /// 适用于日志、调试、状态同步等场景 /// - /// 输入值的类型 - /// 函数返回结果的类型 - /// 要传递给函数的输入值 - /// 接收输入值并返回结果的函数 - /// 函数执行后的结果 - public static TResult Pipe( - this TSource value, - Func func) - => func(value); - - /// - /// Compose:函数组合(f1.Then(f2)) - /// - /// 第一个函数的输入类型 - /// 第一个函数的输出类型,也是第二个函数的输入类型 - /// 第二个函数的输出类型 - /// 第一个要执行的函数 - /// 第二个要执行的函数 - /// 组合后的新函数,先执行first再执行second - public static Func Then( - this Func first, - Func second) - => x => second(first(x)); - - /// - /// Compose:反向组合(f2.After(f1)) - /// - /// 第一个函数的输入类型 - /// 第一个函数的输出类型,也是第二个函数的输入类型 - /// 第二个函数的输出类型 - /// 第二个要执行的函数 - /// 第一个要执行的函数 - /// 组合后的新函数,先执行first再执行second - public static Func After( - this Func second, - Func first) - => x => second(first(x)); - - /// - /// Also:执行操作并返回原值 - /// - /// 输入值的类型 - /// 要执行操作的输入值 - /// 要执行的操作 - /// 原始输入值 - public static TSource Also( - this TSource value, - Action action) + public static T Also( + this T value, + Action action) { action(value); return value; } - - /// - /// Let:将值转换为另一个值 - /// - /// 输入值的类型 - /// 转换结果的类型 - /// 要进行转换的输入值 - /// 用于转换值的函数 - /// 转换后的结果 - public static TResult Let( - this TSource value, - Func transform) - => transform(value); } \ No newline at end of file diff --git a/GFramework.Core/functional/types/NullableExtensions.cs b/GFramework.Core/functional/types/NullableExtensions.cs deleted file mode 100644 index e0ac87f..0000000 --- a/GFramework.Core/functional/types/NullableExtensions.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2026 GeWuYou -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace GFramework.Core.functional.types; - -/// -/// 提供Nullable类型转换为Option类型的扩展方法 -/// -public static class NullableExtensions -{ - /// - /// 将可空引用类型转换为Option类型 - /// - /// 引用类型 - /// 可空的引用类型值 - /// 如果值为null则返回None,否则返回包含该值的Some - public static Option ToOption(this T? value) - where T : class - => value is null - ? Option.None() - : Option.Some(value); - - /// - /// 将可空值类型转换为Option类型 - /// - /// 值类型 - /// 可空的值类型值 - /// 如果值有值则返回包含该值的Some,否则返回None - public static Option ToOption(this T? value) - where T : struct - => value.HasValue - ? Option.Some(value.Value) - : Option.None(); -} \ No newline at end of file diff --git a/GFramework.Core/functional/types/Option.cs b/GFramework.Core/functional/types/Option.cs deleted file mode 100644 index 6586a01..0000000 --- a/GFramework.Core/functional/types/Option.cs +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) 2026 GeWuYou -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace GFramework.Core.functional.types; - -/// -/// 表示一个可能存在也可能不存在的值 -/// -public readonly struct Option -{ - private readonly T _value; - - /// - /// 获取当前Option是否包含值 - /// - public bool IsSome { get; } - - /// - /// 获取当前Option是否为空值 - /// - public bool IsNone => !IsSome; - - /// - /// 使用指定值创建Option实例 - /// - /// 要包装的值 - private Option(T value) - { - _value = value; - IsSome = true; - } - - /// - /// 创建空的Option实例 - /// - /// 占位参数,用于区分构造函数重载 - private Option(bool _) - { - _value = default!; - IsSome = false; - } - - /// - /// 创建包含指定值的Option实例 - /// - /// 要包装的值,不能为null - /// 包含指定值的Option实例 - /// 当value为null时抛出 - public static Option Some(T value) - { - return value is null ? throw new ArgumentNullException(nameof(value)) : new Option(value); - } - - /// - /// 创建空的Option实例 - /// - /// 空的Option实例 - public static Option None() => new(false); - - /// - /// 获取Option中包含的值 - /// - /// 当Option为空时抛出 - public T Value => - IsSome - ? _value - : throw new InvalidOperationException("Option has no value"); -} \ No newline at end of file diff --git a/GFramework.Core/functional/types/OptionExtensions.cs b/GFramework.Core/functional/types/OptionExtensions.cs deleted file mode 100644 index ef82b52..0000000 --- a/GFramework.Core/functional/types/OptionExtensions.cs +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) 2026 GeWuYou -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace GFramework.Core.functional.types; - -/// -/// 提供Option类型的功能扩展方法,支持映射、绑定、过滤和匹配操作 -/// -public static class OptionExtensions -{ - /// - /// 将Option中的值通过指定的映射函数转换为另一种类型的Option - /// - /// 源Option中值的类型 - /// 映射后结果的类型 - /// 要进行映射操作的Option实例 - /// 用于将源值转换为目标值的映射函数 - /// 包含映射后值的新Option实例,如果原Option为空则返回None - public static Option Map( - this Option option, - Func mapper) - { - return option.IsSome - ? Option.Some(mapper(option.Value)) - : Option.None(); - } - - /// - /// 将Option中的值通过指定的绑定函数转换为另一个Option,实现Option的扁平化映射 - /// - /// 源Option中值的类型 - /// 绑定后Option中值的类型 - /// 要进行绑定操作的Option实例 - /// 用于将源值转换为新Option的绑定函数 - /// 绑定函数返回的Option实例,如果原Option为空则返回None - public static Option Bind( - this Option option, - Func> binder) - { - return option.IsSome - ? binder(option.Value) - : Option.None(); - } - - /// - /// 根据指定的谓词函数过滤Option中的值 - /// - /// Option中值的类型 - /// 要进行过滤操作的Option实例 - /// 用于判断值是否满足条件的谓词函数 - /// 如果Option有值且满足谓词条件则返回原Option,否则返回None - public static Option Filter( - this Option option, - Func predicate) - { - return option.IsSome && predicate(option.Value) - ? option - : Option.None(); - } - - /// - /// 对Option进行模式匹配,根据Option的状态执行不同的函数 - /// - /// Option中值的类型 - /// 匹配结果的类型 - /// 要进行匹配操作的Option实例 - /// 当Option包含值时执行的函数 - /// 当Option为空时执行的函数 - /// 根据Option状态执行相应函数后的结果 - public static TResult Match( - this Option option, - Func some, - Func none) - { - return option.IsSome - ? some(option.Value) - : none(); - } -} \ No newline at end of file diff --git a/GFramework.Core/functional/types/OptionValueExtensions.cs b/GFramework.Core/functional/types/OptionValueExtensions.cs deleted file mode 100644 index b0f2786..0000000 --- a/GFramework.Core/functional/types/OptionValueExtensions.cs +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 2026 GeWuYou -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace GFramework.Core.functional.types; - -/// -/// 提供Option类型值的操作扩展方法 -/// -public static class OptionValueExtensions -{ - /// - /// 获取Option中的值,如果Option为空则返回默认值 - /// - /// Option中存储的值的类型 - /// 要获取值的Option对象 - /// 当Option为空时返回的默认值 - /// Option中的值或默认值 - public static T GetOrElse( - this Option option, - T defaultValue) - => option.IsSome ? option.Value : defaultValue; - - /// - /// 获取Option中的值,如果Option为空则通过工厂函数生成默认值 - /// - /// Option中存储的值的类型 - /// 要获取值的Option对象 - /// 当Option为空时用于生成默认值的工厂函数 - /// Option中的值或通过工厂函数生成的值 - public static T GetOrElse( - this Option option, - Func defaultFactory) - => option.IsSome ? option.Value : defaultFactory(); - - /// - /// 获取当前Option,如果当前Option为空则返回备用Option - /// - /// Option中存储的值的类型 - /// 当前Option对象 - /// 当当前Option为空时返回的备用Option - /// 当前Option或备用Option - public static Option OrElse( - this Option option, - Option fallback) - => option.IsSome ? option : fallback; -} \ No newline at end of file diff --git a/GFramework.Core/functional/types/Result.cs b/GFramework.Core/functional/types/Result.cs deleted file mode 100644 index 8208da8..0000000 --- a/GFramework.Core/functional/types/Result.cs +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) 2026 GeWuYou -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace GFramework.Core.functional.types; - -/// -/// 表示一个可能成功也可能失败的计算结果 -/// -/// 成功值的类型 -/// 错误值的类型 -public readonly struct Result -{ - private readonly TSuccess _success; - private readonly TError _error; - - /// - /// 获取当前结果是否为成功状态 - /// - public bool IsSuccess { get; } - - /// - /// 获取当前结果是否为失败状态 - /// - public bool IsFailure => !IsSuccess; - - /// - /// 使用成功值初始化Result实例 - /// - /// 成功值 - private Result(TSuccess success) - { - _success = success; - _error = default!; - IsSuccess = true; - } - - /// - /// 使用错误值初始化Result实例 - /// - /// 错误值 - private Result(TError error) - { - _error = error; - _success = default!; - IsSuccess = false; - } - - /// - /// 创建一个表示成功的Result实例 - /// - /// 成功值 - /// 包含成功值的Result实例 - public static Result Success(TSuccess value) - => new(value); - - /// - /// 创建一个表示失败的Result实例 - /// - /// 错误值 - /// 包含错误值的Result实例 - public static Result Failure(TError error) - => new(error); - - /// - /// 获取成功值,如果结果为失败则抛出异常 - /// - /// 当结果为失败时抛出 - public TSuccess SuccessValue => - IsSuccess - ? _success - : throw new InvalidOperationException("Result is Failure"); - - /// - /// 获取错误值,如果结果为成功则抛出异常 - /// - /// 当结果为成功时抛出 - public TError ErrorValue => - IsFailure - ? _error - : throw new InvalidOperationException("Result is Success"); -} \ No newline at end of file diff --git a/GFramework.Core/functional/types/ResultExtensions.cs b/GFramework.Core/functional/types/ResultExtensions.cs deleted file mode 100644 index a449cee..0000000 --- a/GFramework.Core/functional/types/ResultExtensions.cs +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2026 GeWuYou -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace GFramework.Core.functional.types; - -public static class ResultExtensions -{ - public static Result Map( - this Result result, - Func mapper) - { - return result.IsSuccess - ? Result.Success(mapper(result.SuccessValue)) - : Result.Failure(result.ErrorValue); - } - - public static Result Bind( - this Result result, - Func> binder) - { - return result.IsSuccess - ? binder(result.SuccessValue) - : Result.Failure(result.ErrorValue); - } - - public static Result MapError( - this Result result, - Func mapper) - { - return result.IsFailure - ? Result.Failure(mapper(result.ErrorValue)) - : Result.Success(result.SuccessValue); - } - - public static TResult Match( - this Result result, - Func onSuccess, - Func onFailure) - { - return result.IsSuccess - ? onSuccess(result.SuccessValue) - : onFailure(result.ErrorValue); - } -} \ No newline at end of file diff --git a/GFramework.Core/functional/types/TypeExtensions.cs b/GFramework.Core/functional/types/TypeExtensions.cs deleted file mode 100644 index 937998f..0000000 --- a/GFramework.Core/functional/types/TypeExtensions.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2025 GeWuYou -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -namespace GFramework.Core.functional.types; - -/// -/// 提供类型转换相关的扩展方法 -/// -public static class TypeExtensions -{ - /// - /// 安全类型转换方法,将源类型转换为目标类型 - /// 如果转换失败或值为null,则返回null而不抛出异常 - /// - /// 源类型参数 - /// 目标类型参数,必须为引用类型 - /// 需要进行类型转换的源值 - /// 转换成功时返回目标类型实例,失败时返回null - public static TResult? As( - this TSource value) - where TResult : class - => value as TResult; - - /// - /// 强制类型转换方法,将对象转换为指定的目标类型 - /// 转换失败时会抛出InvalidCastException异常 - /// - /// 目标类型参数 - /// 需要进行强制类型转换的对象 - /// 转换后的目标类型实例 - /// 当转换失败时抛出此异常 - public static TResult Cast( - this object value) - => (TResult)value; -} diff --git a/GFramework.Game/GFramework.Game.csproj b/GFramework.Game/GFramework.Game.csproj index 5e56a18..799cbae 100644 --- a/GFramework.Game/GFramework.Game.csproj +++ b/GFramework.Game/GFramework.Game.csproj @@ -11,6 +11,7 @@ + diff --git a/GFramework.Game/GlobalUsings.cs b/GFramework.Game/GlobalUsings.cs index 74db065..c2615ab 100644 --- a/GFramework.Game/GlobalUsings.cs +++ b/GFramework.Game/GlobalUsings.cs @@ -16,4 +16,7 @@ global using System.Collections.Generic; global using System.Collections.Concurrent; global using System.Linq; global using System.Threading; -global using System.Threading.Tasks; \ No newline at end of file +global using System.Threading.Tasks; +global using LanguageExt.Common; +global using LanguageExt.Effects; +global using LanguageExt.Pretty; \ No newline at end of file diff --git a/GFramework.Godot/GFramework.Godot.csproj b/GFramework.Godot/GFramework.Godot.csproj index ff471e8..c28514a 100644 --- a/GFramework.Godot/GFramework.Godot.csproj +++ b/GFramework.Godot/GFramework.Godot.csproj @@ -11,6 +11,7 @@ + diff --git a/GFramework.Godot/GlobalUsings.cs b/GFramework.Godot/GlobalUsings.cs index 4d27181..05d852c 100644 --- a/GFramework.Godot/GlobalUsings.cs +++ b/GFramework.Godot/GlobalUsings.cs @@ -15,4 +15,7 @@ global using System; global using System.Collections.Generic; global using System.Linq; global using System.Threading; -global using System.Threading.Tasks; \ No newline at end of file +global using System.Threading.Tasks; +global using LanguageExt.Common; +global using LanguageExt.Effects; +global using LanguageExt.Pretty; \ No newline at end of file diff --git a/GFramework.Godot/storage/GodotFileStorage.cs b/GFramework.Godot/storage/GodotFileStorage.cs index 7ac1568..5a27bf5 100644 --- a/GFramework.Godot/storage/GodotFileStorage.cs +++ b/GFramework.Godot/storage/GodotFileStorage.cs @@ -5,6 +5,7 @@ using GFramework.Core.Abstractions.serializer; using GFramework.Core.Abstractions.storage; using GFramework.Godot.extensions; using Godot; +using Error = Godot.Error; using FileAccess = Godot.FileAccess; namespace GFramework.Godot.storage;