From 43dcae0cf534d5fa49a24ebac346a880ca49d321 Mon Sep 17 00:00:00 2001 From: GeWuYou <95328647+GeWuYou@users.noreply.github.com> Date: Sat, 31 Jan 2026 15:11:33 +0800 Subject: [PATCH] =?UTF-8?q?refactor(pipe):=20=E9=87=8D=E6=9E=84=E5=87=BD?= =?UTF-8?q?=E6=95=B0=E5=BC=8F=E7=BC=96=E7=A8=8B=E6=89=A9=E5=B1=95=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E4=B8=BA=E6=A8=A1=E5=9D=97=E5=8C=96=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将原有的PipeExtensionsTests拆分为多个专门的测试类 - 创建ControlExtensionsTests用于控制流函数测试 - 创建EnumerableExtensionsTests用于集合操作函数测试 - 创建FunctionExtensionsTests用于高级函数操作测试 - 移除旧的综合测试文件中的多余测试方法 - 更新文档结构以反映新的模块化组织方式 - 重新整理README.md文档为模块化分类说明 --- .../collections/EnumerableExtensionsTests.cs | 72 +++ .../control/ControlExtensionsTests.cs | 229 ++++++++ .../functions/FunctionExtensionsTests.cs | 172 ++++++ .../functional/pipe/PipeExtensionsTests.cs | 498 +----------------- .../functional/types/TypeExtensionsTests.cs | 69 +++ .../functional/{pipe => }/README.md | 170 +++--- 6 files changed, 644 insertions(+), 566 deletions(-) create mode 100644 GFramework.Core.Tests/functional/collections/EnumerableExtensionsTests.cs create mode 100644 GFramework.Core.Tests/functional/control/ControlExtensionsTests.cs create mode 100644 GFramework.Core.Tests/functional/functions/FunctionExtensionsTests.cs create mode 100644 GFramework.Core.Tests/functional/types/TypeExtensionsTests.cs rename GFramework.Core/functional/{pipe => }/README.md (70%) diff --git a/GFramework.Core.Tests/functional/collections/EnumerableExtensionsTests.cs b/GFramework.Core.Tests/functional/collections/EnumerableExtensionsTests.cs new file mode 100644 index 0000000..472e119 --- /dev/null +++ b/GFramework.Core.Tests/functional/collections/EnumerableExtensionsTests.cs @@ -0,0 +1,72 @@ +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 new file mode 100644 index 0000000..ba5ab69 --- /dev/null +++ b/GFramework.Core.Tests/functional/control/ControlExtensionsTests.cs @@ -0,0 +1,229 @@ +using GFramework.Core.functional.control; +using NUnit.Framework; + +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方法 - 验证条件为真时返回原值 + /// + [Test] + public void TakeIf_Should_Return_Value_When_Condition_Is_True() + { + // Arrange + string str = "Hello"; + + // Act + var result = str.TakeIf(s => s.Length > 3); + + // Assert + Assert.That(result, Is.EqualTo("Hello")); + } + + /// + /// 测试TakeIf方法 - 验证条件为假时返回null + /// + [Test] + public void TakeIf_Should_Return_Null_When_Condition_Is_False() + { + // Arrange + string str = "Hi"; + + // Act + var result = str.TakeIf(s => s.Length > 3); + + // Assert + Assert.That(result, Is.Null); + } + + #endregion + + #region TakeUnless Tests + + /// + /// 测试TakeUnless方法 - 验证条件为假时返回原值 + /// + [Test] + public void TakeUnless_Should_Return_Value_When_Condition_Is_False() + { + // Arrange + string str = "Hi"; + + // Act + var result = str.TakeUnless(s => s.Length > 3); + + // Assert + Assert.That(result, Is.EqualTo("Hi")); + } + + /// + /// 测试TakeUnless方法 - 验证条件为真时返回null + /// + [Test] + public void TakeUnless_Should_Return_Null_When_Condition_Is_True() + { + // 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 new file mode 100644 index 0000000..7b259cd --- /dev/null +++ b/GFramework.Core.Tests/functional/functions/FunctionExtensionsTests.cs @@ -0,0 +1,172 @@ +using GFramework.Core.functional.functions; +using NUnit.Framework; + +namespace GFramework.Core.Tests.functional.functions; + +/// +/// FunctionExtensions扩展方法测试类,用于验证高级函数式编程扩展方法的正确性 +/// 包括柯里化、偏函数应用、重复执行、安全执行和缓存等功能的测试 +/// +[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方法 - 验证部分应用函数功能 + /// + [Test] + public void Partial_Should_Fix_First_Argument_Of_Binary_Function() + { + // 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方法 - 验证重复执行函数功能 + /// + [Test] + public void Repeat_Should_Execute_Function_N_Times() + { + // 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 5d0c6db..434cba7 100644 --- a/GFramework.Core.Tests/functional/pipe/PipeExtensionsTests.cs +++ b/GFramework.Core.Tests/functional/pipe/PipeExtensionsTests.cs @@ -1,12 +1,11 @@ -using GFramework.Core.extensions; using GFramework.Core.functional.pipe; using NUnit.Framework; namespace GFramework.Core.Tests.functional.pipe; /// -/// PipeExtensions扩展方法测试类,用于验证函数式编程扩展方法的正确性 -/// 包括管道操作、函数组合、柯里化、模式匹配等多种函数式编程功能的测试 +/// PipeExtensions扩展方法测试类,用于验证管道和函数组合扩展方法的正确性 +/// 包括管道操作、函数组合等核心功能的测试 /// [TestFixture] public class PipeExtensionsTests @@ -101,66 +100,6 @@ public class PipeExtensionsTests #endregion - #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 - #region Apply Tests /// @@ -181,272 +120,6 @@ public class PipeExtensionsTests #endregion - #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方法 - 验证部分应用函数功能 - /// - [Test] - public void Partial_Should_Fix_First_Argument_Of_Binary_Function() - { - // 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 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 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 - #region Also Tests /// @@ -488,171 +161,4 @@ public class PipeExtensionsTests } #endregion - - #region TakeIf Tests - - /// - /// 测试TakeIf方法 - 验证条件为真时返回原值 - /// - [Test] - public void TakeIf_Should_Return_Value_When_Condition_Is_True() - { - // Arrange - string str = "Hello"; - - // Act - var result = str.TakeIf(s => s.Length > 3); - - // Assert - Assert.That(result, Is.EqualTo("Hello")); - } - - /// - /// 测试TakeIf方法 - 验证条件为假时返回null - /// - [Test] - public void TakeIf_Should_Return_Null_When_Condition_Is_False() - { - // Arrange - string str = "Hi"; - - // Act - var result = str.TakeIf(s => s.Length > 3); - - // Assert - Assert.That(result, Is.Null); - } - - #endregion - - #region TakeUnless Tests - - /// - /// 测试TakeUnless方法 - 验证条件为假时返回原值 - /// - [Test] - public void TakeUnless_Should_Return_Value_When_Condition_Is_False() - { - // Arrange - string str = "Hi"; - - // Act - var result = str.TakeUnless(s => s.Length > 3); - - // Assert - Assert.That(result, Is.EqualTo("Hi")); - } - - /// - /// 测试TakeUnless方法 - 验证条件为真时返回null - /// - [Test] - public void TakeUnless_Should_Return_Null_When_Condition_Is_True() - { - // Arrange - string str = "Hello"; - - // Act - var result = str.TakeUnless(s => s.Length > 3); - - // Assert - Assert.That(result, Is.Null); - } - - #endregion - - #region Repeat Tests - - /// - /// 测试Repeat方法 - 验证重复执行函数功能 - /// - [Test] - public void Repeat_Should_Execute_Function_N_Times() - { - // 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/types/TypeExtensionsTests.cs b/GFramework.Core.Tests/functional/types/TypeExtensionsTests.cs new file mode 100644 index 0000000..2164ab9 --- /dev/null +++ b/GFramework.Core.Tests/functional/types/TypeExtensionsTests.cs @@ -0,0 +1,69 @@ +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/functional/pipe/README.md b/GFramework.Core/functional/README.md similarity index 70% rename from GFramework.Core/functional/pipe/README.md rename to GFramework.Core/functional/README.md index 36d1082..bd7982b 100644 --- a/GFramework.Core/functional/pipe/README.md +++ b/GFramework.Core/functional/README.md @@ -1,20 +1,24 @@ -# Pipe Extensions - 函数式编程扩展方法 +# Functional Extensions - 函数式编程扩展方法 -提供了一系列用于函数式编程的管道和组合操作扩展方法。 +提供了一系列用于函数式编程的扩展方法,已按功能拆分为多个类别。 ## 功能概览 -这些扩展方法实现了函数式编程的核心概念,包括管道操作、函数组合、柯里化、模式匹配等功能,使C#代码更加简洁和函数式。 +这些扩展方法实现了函数式编程的核心概念,包括管道操作、函数组合、集合操作、控制流、类型转换等功能,使C#代码更加简洁和函数式。 -## 方法列表及用法 +## 模块分类 -### 1. Pipe - 管道操作 +### 1. Pipe Extensions - 管道和函数组合操作 +位于 `GFramework.Core.functional.pipe` 命名空间,提供管道和函数组合操作。 + +#### 方法列表及用法: +- **Pipe** - 把值送进函数 ```csharp // 将值传入函数进行处理 var result = 5.Pipe(x => x * 2); // 结果为 10 ``` -### 2. Then - 函数组合 +- **Then** - 函数组合(f1.Then(f2)) ```csharp // 组合两个函数,先执行first再执行second Func addTwo = x => x + 2; @@ -23,7 +27,7 @@ var composed = addTwo.Then(multiplyByThree); // 先+2再*3 var result = composed(5); // (5+2)*3 = 21 ``` -### 3. After - 反向组合 +- **After** - 反向函数组合 ```csharp // 与Then相反,以不同的顺序组合函数 Func multiplyByThree = x => x * 3; @@ -32,66 +36,61 @@ var composed = multiplyByThree.After(addTwo); // 先+2再*3 var result = composed(5); // (5+2)*3 = 21 ``` -### 4. Tap - 执行副作用 +- **Tap** - 执行副作用操作但返回原值 ```csharp // 执行副作用操作但返回原值,常用于调试或日志记录 var value = 42.Tap(Console.WriteLine); // 输出42,但value仍为42 ``` -### 5. Map - 映射操作 -```csharp -// 对集合中的每个元素应用函数 -var numbers = new[] {1, 2, 3, 4}; -var squared = numbers.Map(x => x * x); // {1, 4, 9, 16} -``` - -### 6. Filter - 过滤操作 -```csharp -// 过滤集合中的元素 -var numbers = new[] {1, 2, 3, 4, 5, 6}; -var evens = numbers.Filter(x => x % 2 == 0); // {2, 4, 6} -``` - -### 7. Reduce - 归约操作 -```csharp -// 将集合归约为单个值 -var numbers = new[] {1, 2, 3, 4}; -var sum = numbers.Reduce(0, (acc, x) => acc + x); // 10 -``` - -### 8. Apply - 应用函数 +- **Apply** - 将函数应用于值 ```csharp // 将参数应用于函数 Func multiplyByTwo = x => x * 2; var result = multiplyByTwo.Apply(5); // 10 ``` -### 9. Curry - 柯里化 +- **Also** - 执行操作并返回原值 ```csharp -// 将多参数函数转换为链式单参数函数 -Func add = (x, y) => x + y; -var curriedAdd = add.Curry(); // 返回 Func> -var addFive = curriedAdd(5); // 返回 Func -var result = addFive(3); // 8 +// 执行操作并返回原值 +var value = 42.Also(Console.WriteLine); // 输出42,返回42 ``` -### 10. Uncurry - 取消柯里化 +- **Let** - 将值转换为另一个值 ```csharp -// 将柯里化函数转换回多参数函数 -var curriedAdd = ((Func)((x, y) => x + y)).Curry(); -var uncurriedAdd = curriedAdd.Uncurry(); // 返回 Func -var result = uncurriedAdd(5, 3); // 8 +// 转换值 +var result = 5.Let(x => x * 2); // 10 ``` -### 11. Partial - 部分应用 +### 2. Collections Extensions - 集合操作 +位于 `GFramework.Core.functional.collections` 命名空间,提供对集合的函数式操作。 + +#### 方法列表及用法: +- **Map** - 映射操作 ```csharp -// 固定函数的部分参数 -Func multiply = (x, y) => x * y; -var double = multiply.Partial(2); // 固定第一个参数为2 -var result = double(5); // 10 +// 对集合中的每个元素应用函数 +var numbers = new[] {1, 2, 3, 4}; +var squared = numbers.Map(x => x * x); // {1, 4, 9, 16} ``` -### 12. Match - 模式匹配 +- **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( @@ -101,7 +100,7 @@ var result = 5.Match( ); // "正数" ``` -### 13. MatchOrDefault - 带默认值的模式匹配 +- **MatchOrDefault** - 带默认值的模式匹配 ```csharp // 模式匹配,无匹配时返回默认值 var result = 0.MatchOrDefault("未知数字", @@ -110,7 +109,7 @@ var result = 0.MatchOrDefault("未知数字", ); // "未知数字" ``` -### 14. If / IfElse - 条件执行 +- **If / IfElse** - 条件执行 ```csharp // 条件执行操作 var result = 5.If(x => x > 0, x => x * 2); // 10 (因为5>0,所以乘以2) @@ -121,24 +120,7 @@ var result2 = 5.IfElse( ); // 6 (因为5不大于10,所以+1) ``` -### 15. As / Cast - 类型转换 -```csharp -// 安全类型转换 -object obj = "Hello"; -var str = obj.As(); // "Hello" -var str2 = obj.Cast(); // "Hello" (强制转换) -``` - -### 16. Also / Let - 副作用和转换 -```csharp -// 执行操作并返回原值 -var value = 42.Also(Console.WriteLine); // 输出42,返回42 - -// 转换值 -var result = 5.Let(x => x * 2); // 10 -``` - -### 17. TakeIf / TakeUnless - 条件取值 +- **TakeIf / TakeUnless** - 条件取值 ```csharp // 条件为真时返回值,否则返回null string str = "Hello"; @@ -150,20 +132,49 @@ var result3 = str.TakeUnless(s => s.Length > 10); // "Hello" (因为长度不大 var result4 = str.TakeUnless(s => s.Length > 3); // null (因为长度大于3) ``` -### 18. Repeat - 重复执行 +### 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 ``` -### 19. Try - 安全执行 +- **Try** - 安全执行 ```csharp // 安全执行可能抛出异常的函数 var (success, result, error) = 10.Try(x => 100 / x); // 成功,result为10 var (success2, result2, error2) = 0.Try(x => 100 / x); // 失败,success2为false ``` -### 20. Memoize - 缓存结果 +- **Memoize** - 缓存结果 ```csharp // 缓存函数结果以提高性能 Func expensiveFunction = x => @@ -177,6 +188,25 @@ 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" +``` + ## 使用示例 ### 链式操作