mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-22 10:34:30 +08:00
refactor(functional): 重构函数式编程扩展模块
- 移除 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]
This commit is contained in:
parent
3493d6a481
commit
b2e8ed9787
@ -1,72 +0,0 @@
|
||||
using GFramework.Core.functional.collections;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GFramework.Core.Tests.functional.collections;
|
||||
|
||||
/// <summary>
|
||||
/// EnumerableExtensions扩展方法测试类,用于验证集合函数式编程扩展方法的正确性
|
||||
/// 包括Map、Filter、Reduce等集合操作功能的测试
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class EnumerableExtensionsTests
|
||||
{
|
||||
#region Map Tests
|
||||
|
||||
/// <summary>
|
||||
/// 测试Map方法 - 验证集合中的每个元素都能被正确转换
|
||||
/// </summary>
|
||||
[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
|
||||
|
||||
/// <summary>
|
||||
/// 测试Filter方法 - 验证集合能够根据条件正确过滤
|
||||
/// </summary>
|
||||
[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
|
||||
|
||||
/// <summary>
|
||||
/// 测试Reduce方法 - 验证集合能够正确归约为单个值
|
||||
/// </summary>
|
||||
[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
|
||||
}
|
||||
@ -5,158 +5,10 @@ namespace GFramework.Core.Tests.functional.control;
|
||||
|
||||
/// <summary>
|
||||
/// ControlExtensions扩展方法测试类,用于验证控制流函数式编程扩展方法的正确性
|
||||
/// 包括模式匹配、条件执行等控制流功能的测试
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class ControlExtensionsTests
|
||||
{
|
||||
#region Match Tests
|
||||
|
||||
/// <summary>
|
||||
/// 测试Match方法 - 验证模式匹配功能
|
||||
/// </summary>
|
||||
[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"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试Match方法 - 验证无匹配时抛出异常
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Match_Should_Throw_Exception_When_No_Case_Matches()
|
||||
{
|
||||
// Arrange
|
||||
var value = 10;
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<InvalidOperationException>(() =>
|
||||
value.Match(
|
||||
(x => x < 0, _ => "negative"),
|
||||
(x => x > 10, _ => "large positive")
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region MatchOrDefault Tests
|
||||
|
||||
/// <summary>
|
||||
/// 测试MatchOrDefault方法 - 验证模式匹配带默认值功能
|
||||
/// </summary>
|
||||
[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
|
||||
|
||||
/// <summary>
|
||||
/// 测试If方法 - 验证条件执行功能
|
||||
/// </summary>
|
||||
[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));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试If方法 - 验证条件为假时不执行转换函数
|
||||
/// </summary>
|
||||
[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
|
||||
|
||||
/// <summary>
|
||||
/// 测试IfElse方法 - 验证条件分支功能
|
||||
/// </summary>
|
||||
[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));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试IfElse方法 - 验证条件为假时执行else分支
|
||||
/// </summary>
|
||||
[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
|
||||
|
||||
/// <summary>
|
||||
/// 测试TakeIf方法 - 验证条件为真时返回原值
|
||||
/// </summary>
|
||||
@ -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"));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 测试TakeIf方法 - 验证条件为假时返回null
|
||||
/// </summary>
|
||||
@ -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
|
||||
|
||||
/// <summary>
|
||||
/// 测试TakeUnless方法 - 验证条件为假时返回原值
|
||||
/// </summary>
|
||||
@ -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"));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 测试TakeUnless方法 - 验证条件为真时返回null
|
||||
/// </summary>
|
||||
@ -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
|
||||
}
|
||||
@ -10,52 +10,6 @@ namespace GFramework.Core.Tests.functional.functions;
|
||||
[TestFixture]
|
||||
public class FunctionExtensionsTests
|
||||
{
|
||||
#region Curry Tests
|
||||
|
||||
/// <summary>
|
||||
/// 测试Curry方法 - 验证二参数函数能够正确柯里化
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Curry_Should_Convert_Binary_Function_To_Curried_Form()
|
||||
{
|
||||
// Arrange
|
||||
Func<int, int, int> 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
|
||||
|
||||
/// <summary>
|
||||
/// 测试Uncurry方法 - 验证柯里化函数能够正确还原为二参数函数
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Uncurry_Should_Convert_Curried_Function_Back_To_Binary_Form()
|
||||
{
|
||||
// Arrange
|
||||
Func<int, int, int> 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
|
||||
|
||||
/// <summary>
|
||||
/// 测试Partial方法 - 验证部分应用函数功能
|
||||
/// </summary>
|
||||
@ -64,19 +18,15 @@ public class FunctionExtensionsTests
|
||||
{
|
||||
// Arrange
|
||||
Func<int, int, int> 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
|
||||
|
||||
/// <summary>
|
||||
/// 测试Repeat方法 - 验证重复执行函数功能
|
||||
/// </summary>
|
||||
@ -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
|
||||
|
||||
/// <summary>
|
||||
/// 测试Try方法 - 验证安全执行成功情况
|
||||
/// </summary>
|
||||
[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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试Try方法 - 验证安全执行异常情况
|
||||
/// </summary>
|
||||
[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<DivideByZeroException>());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Memoize Tests
|
||||
|
||||
/// <summary>
|
||||
/// 测试Memoize方法 - 验证函数结果缓存功能
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Memoize_Should_Cache_Function_Results()
|
||||
{
|
||||
// Arrange
|
||||
var callCount = 0;
|
||||
Func<int, int> 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
|
||||
}
|
||||
@ -10,63 +10,6 @@ namespace GFramework.Core.Tests.functional.pipe;
|
||||
[TestFixture]
|
||||
public class PipeExtensionsTests
|
||||
{
|
||||
/// <summary>
|
||||
/// 测试Pipe方法 - 验证值能够正确传递给函数并返回结果
|
||||
/// </summary>
|
||||
[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));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试Then方法 - 验证两个函数能够正确组合执行
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Then_Should_Compose_Two_Functions()
|
||||
{
|
||||
// Arrange
|
||||
Func<int, int> addTwo = x => x + 2;
|
||||
|
||||
// Act
|
||||
var composed = addTwo.Then((Func<int, int>)MultiplyByThree);
|
||||
var result = composed(5);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo(21)); // (5+2)*3 = 21
|
||||
return;
|
||||
|
||||
int MultiplyByThree(int x) => x * 3;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试After方法 - 验证反向函数组合的正确性
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void After_Should_Compose_Functions_In_Reversed_Order()
|
||||
{
|
||||
// Arrange
|
||||
Func<int, int> multiplyByThree = x => x * 3;
|
||||
|
||||
// Act
|
||||
var composed = multiplyByThree.After((Func<int, int>)AddTwo);
|
||||
var result = composed(5);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo(21)); // (5+2)*3 = 21
|
||||
return;
|
||||
|
||||
int AddTwo(int x) => x + 2;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 测试Also方法 - 验证执行操作后返回原值功能
|
||||
/// </summary>
|
||||
@ -84,20 +27,4 @@ public class PipeExtensionsTests
|
||||
Assert.That(result, Is.EqualTo(42));
|
||||
Assert.That(capturedValue, Is.EqualTo(42));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试Let方法 - 验证值转换功能
|
||||
/// </summary>
|
||||
[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));
|
||||
}
|
||||
}
|
||||
@ -1,78 +0,0 @@
|
||||
using GFramework.Core.functional.types;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GFramework.Core.Tests.functional.types;
|
||||
|
||||
/// <summary>
|
||||
/// NullableExtensions扩展方法测试类,用于验证可空类型转换为Option类型的功能
|
||||
/// 包括引用类型和值类型的可空转换测试
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class NullableExtensionsTests
|
||||
{
|
||||
/// <summary>
|
||||
/// 测试引用类型可空转换 - 验证非null值转换为Some
|
||||
/// </summary>
|
||||
[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"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试引用类型可空转换 - 验证null值转换为None
|
||||
/// </summary>
|
||||
[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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试值类型可空转换 - 验证有值的可空值类型转换为Some
|
||||
/// </summary>
|
||||
[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));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试值类型可空转换 - 验证无值的可空值类型转换为None
|
||||
/// </summary>
|
||||
[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);
|
||||
}
|
||||
}
|
||||
@ -1,181 +0,0 @@
|
||||
using GFramework.Core.functional.types;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GFramework.Core.Tests.functional.types;
|
||||
|
||||
/// <summary>
|
||||
/// OptionExtensions扩展方法测试类,用于验证Option类型的功能扩展方法
|
||||
/// 包括映射、绑定、过滤和匹配操作等功能的测试
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class OptionExtensionsTests
|
||||
{
|
||||
/// <summary>
|
||||
/// 测试Map方法 - 验证Some值能正确映射
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Option_Map_Should_Transform_Some_Value()
|
||||
{
|
||||
// Arrange
|
||||
var option = Option<string>.Some("hello");
|
||||
|
||||
// Act
|
||||
var result = option.Map(s => s.Length);
|
||||
|
||||
// Assert
|
||||
Assert.That(result.IsSome, Is.True);
|
||||
Assert.That(result.Value, Is.EqualTo(5));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试Map方法 - 验证None映射后仍为None
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Option_Map_Should_Return_None_For_None()
|
||||
{
|
||||
// Arrange
|
||||
var option = Option<string>.None();
|
||||
|
||||
// Act
|
||||
var result = option.Map(s => s.Length);
|
||||
|
||||
// Assert
|
||||
Assert.That(result.IsNone, Is.True);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试Bind方法 - 验证Some值能正确绑定到另一个Option
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Option_Bind_Should_Transform_Some_To_Another_Option()
|
||||
{
|
||||
// Arrange
|
||||
var option = Option<string>.Some("hello");
|
||||
|
||||
// Act
|
||||
var result = option.Bind(s => s.Length > 3 ? Option<int>.Some(s.Length) : Option<int>.None());
|
||||
|
||||
// Assert
|
||||
Assert.That(result.IsSome, Is.True);
|
||||
Assert.That(result.Value, Is.EqualTo(5));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试Bind方法 - 验证None绑定后仍为None
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Option_Bind_Should_Return_None_For_None()
|
||||
{
|
||||
// Arrange
|
||||
var option = Option<string>.None();
|
||||
|
||||
// Act
|
||||
var result = option.Bind(s => Option<int>.Some(s.Length));
|
||||
|
||||
// Assert
|
||||
Assert.That(result.IsNone, Is.True);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试Bind方法 - 验证Some值绑定到None的情况
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Option_Bind_Should_Return_None_When_Binder_Returns_None()
|
||||
{
|
||||
// Arrange
|
||||
var option = Option<string>.Some("hi"); // 长度小于3
|
||||
|
||||
// Act
|
||||
var result = option.Bind(s => s.Length > 3 ? Option<int>.Some(s.Length) : Option<int>.None());
|
||||
|
||||
// Assert
|
||||
Assert.That(result.IsNone, Is.True);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试Filter方法 - 验证满足条件的Some值保留
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Option_Filter_Should_Keep_Some_When_Predicate_Matches()
|
||||
{
|
||||
// Arrange
|
||||
var option = Option<string>.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"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试Filter方法 - 验证不满足条件的Some值变为None
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Option_Filter_Should_Return_None_When_Predicate_Does_Not_Match()
|
||||
{
|
||||
// Arrange
|
||||
var option = Option<string>.Some("hi");
|
||||
|
||||
// Act
|
||||
var result = option.Filter(s => s.Length > 3);
|
||||
|
||||
// Assert
|
||||
Assert.That(result.IsNone, Is.True);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试Filter方法 - 验证None过滤后仍为None
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Option_Filter_Should_Return_None_For_None()
|
||||
{
|
||||
// Arrange
|
||||
var option = Option<string>.None();
|
||||
|
||||
// Act
|
||||
var result = option.Filter(s => s.Length > 3);
|
||||
|
||||
// Assert
|
||||
Assert.That(result.IsNone, Is.True);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试Match方法 - 验证Some值执行some分支
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Option_Match_Should_Execute_Some_Branch_For_Some()
|
||||
{
|
||||
// Arrange
|
||||
var option = Option<string>.Some("hello");
|
||||
|
||||
// Act
|
||||
var result = option.Match(
|
||||
some: s => $"Value: {s}",
|
||||
none: () => "No value"
|
||||
);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo("Value: hello"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试Match方法 - 验证None值执行none分支
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Option_Match_Should_Execute_None_Branch_For_None()
|
||||
{
|
||||
// Arrange
|
||||
var option = Option<string>.None();
|
||||
|
||||
// Act
|
||||
var result = option.Match(
|
||||
some: s => $"Value: {s}",
|
||||
none: () => "No value"
|
||||
);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo("No value"));
|
||||
}
|
||||
}
|
||||
@ -1,70 +0,0 @@
|
||||
using GFramework.Core.functional.types;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GFramework.Core.Tests.functional.types;
|
||||
|
||||
/// <summary>
|
||||
/// Option类型测试类,用于验证Option类型的基本功能
|
||||
/// 包括创建Some和None实例、值访问等功能的测试
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class OptionTests
|
||||
{
|
||||
/// <summary>
|
||||
/// 测试创建Some实例 - 验证非null值能正确创建Some
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Option_Some_Should_Create_WithValue()
|
||||
{
|
||||
// Arrange
|
||||
var value = "Hello";
|
||||
|
||||
// Act
|
||||
var option = Option<string>.Some(value);
|
||||
|
||||
// Assert
|
||||
Assert.That(option.IsSome, Is.True);
|
||||
Assert.That(option.IsNone, Is.False);
|
||||
Assert.That(option.Value, Is.EqualTo(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试创建Some实例 - 验证null值时抛出异常
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Option_Some_Should_Throw_When_Value_Is_Null()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.Throws<ArgumentNullException>(() => Option<string>.Some(null!));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试创建None实例 - 验证能正确创建None
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Option_None_Should_Create_Empty_Instance()
|
||||
{
|
||||
// Act
|
||||
var option = Option<string>.None();
|
||||
|
||||
// Assert
|
||||
Assert.That(option.IsNone, Is.True);
|
||||
Assert.That(option.IsSome, Is.False);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试访问None的值 - 验证抛出异常
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Option_None_Value_Access_Should_Throw_Exception()
|
||||
{
|
||||
// Arrange
|
||||
var option = Option<string>.None();
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<InvalidOperationException>(() =>
|
||||
{
|
||||
var _ = option.Value;
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1,141 +0,0 @@
|
||||
using GFramework.Core.functional.types;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GFramework.Core.Tests.functional.types;
|
||||
|
||||
/// <summary>
|
||||
/// OptionValueExtensions扩展方法测试类,用于验证Option类型值的操作扩展方法
|
||||
/// 包括获取默认值、备选Option等功能的测试
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class OptionValueExtensionsTests
|
||||
{
|
||||
/// <summary>
|
||||
/// 测试GetOrElse方法 - 验证Some值直接返回其值
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void OptionValueExtensions_GetOrElse_Should_Return_Value_For_Some()
|
||||
{
|
||||
// Arrange
|
||||
var option = Option<string>.Some("actual value");
|
||||
|
||||
// Act
|
||||
var result = option.GetOrElse("default value");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo("actual value"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试GetOrElse方法 - 验证None值返回默认值
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void OptionValueExtensions_GetOrElse_Should_Return_Default_For_None()
|
||||
{
|
||||
// Arrange
|
||||
var option = Option<string>.None();
|
||||
|
||||
// Act
|
||||
var result = option.GetOrElse("default value");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo("default value"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试GetOrElse方法(工厂函数) - 验证Some值直接返回其值(不调用工厂)
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void OptionValueExtensions_GetOrElse_With_Factory_Should_Return_Value_For_Some()
|
||||
{
|
||||
// Arrange
|
||||
var option = Option<string>.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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试GetOrElse方法(工厂函数) - 验证None值调用工厂函数
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void OptionValueExtensions_GetOrElse_With_Factory_Should_Call_Factory_For_None()
|
||||
{
|
||||
// Arrange
|
||||
var option = Option<string>.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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试OrElse方法 - 验证Some值返回自身
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void OptionValueExtensions_OrElse_Should_Return_Self_For_Some()
|
||||
{
|
||||
// Arrange
|
||||
var option = Option<string>.Some("primary value");
|
||||
var fallback = Option<string>.Some("fallback value");
|
||||
|
||||
// Act
|
||||
var result = option.OrElse(fallback);
|
||||
|
||||
// Assert
|
||||
Assert.That(result.IsSome, Is.True);
|
||||
Assert.That(result.Value, Is.EqualTo("primary value"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试OrElse方法 - 验证None值返回备选Option
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void OptionValueExtensions_OrElse_Should_Return_Fallback_For_None()
|
||||
{
|
||||
// Arrange
|
||||
var option = Option<string>.None();
|
||||
var fallback = Option<string>.Some("fallback value");
|
||||
|
||||
// Act
|
||||
var result = option.OrElse(fallback);
|
||||
|
||||
// Assert
|
||||
Assert.That(result.IsSome, Is.True);
|
||||
Assert.That(result.Value, Is.EqualTo("fallback value"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试OrElse方法 - 验证None值返回备选None
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void OptionValueExtensions_OrElse_Should_Return_Fallback_None_For_None()
|
||||
{
|
||||
// Arrange
|
||||
var option = Option<string>.None();
|
||||
var fallback = Option<string>.None();
|
||||
|
||||
// Act
|
||||
var result = option.OrElse(fallback);
|
||||
|
||||
// Assert
|
||||
Assert.That(result.IsNone, Is.True);
|
||||
}
|
||||
}
|
||||
@ -1,171 +0,0 @@
|
||||
using GFramework.Core.functional.types;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GFramework.Core.Tests.functional.types;
|
||||
|
||||
/// <summary>
|
||||
/// ResultExtensions扩展方法测试类,用于验证Result类型的功能扩展方法
|
||||
/// 包括映射、绑定、错误映射和匹配操作等功能的测试
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class ResultExtensionsTests
|
||||
{
|
||||
/// <summary>
|
||||
/// 测试Map方法 - 验证Success值能正确映射
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Result_Map_Should_Transform_Success_Value()
|
||||
{
|
||||
// Arrange
|
||||
var result = Result<string, string>.Success("hello");
|
||||
|
||||
// Act
|
||||
var mappedResult = result.Map(s => s.Length);
|
||||
|
||||
// Assert
|
||||
Assert.That(mappedResult.IsSuccess, Is.True);
|
||||
Assert.That(mappedResult.SuccessValue, Is.EqualTo(5));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试Map方法 - 验证Failure映射后仍保持Failure状态
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Result_Map_Should_Keep_Failure_For_Failure()
|
||||
{
|
||||
// Arrange
|
||||
var result = Result<string, string>.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"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试Bind方法 - 验证Success值能正确绑定到另一个Result
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Result_Bind_Should_Transform_Success_To_Another_Result()
|
||||
{
|
||||
// Arrange
|
||||
var result = Result<string, string>.Success("hello");
|
||||
|
||||
// Act
|
||||
var boundResult = result.Bind(s =>
|
||||
s.Length > 3 ? Result<int, string>.Success(s.Length) : Result<int, string>.Failure("Length too small"));
|
||||
|
||||
// Assert
|
||||
Assert.That(boundResult.IsSuccess, Is.True);
|
||||
Assert.That(boundResult.SuccessValue, Is.EqualTo(5));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试Bind方法 - 验证Failure绑定后仍保持Failure状态
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Result_Bind_Should_Keep_Failure_For_Failure()
|
||||
{
|
||||
// Arrange
|
||||
var result = Result<string, string>.Failure("initial error");
|
||||
|
||||
// Act
|
||||
var boundResult = result.Bind(s => Result<int, string>.Success(s.Length));
|
||||
|
||||
// Assert
|
||||
Assert.That(boundResult.IsFailure, Is.True);
|
||||
Assert.That(boundResult.ErrorValue, Is.EqualTo("initial error"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试Bind方法 - 验证Success值绑定到Failure的情况
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Result_Bind_Should_Allow_Transition_To_Failure()
|
||||
{
|
||||
// Arrange
|
||||
var result = Result<string, string>.Success("hi"); // 长度小于3
|
||||
|
||||
// Act
|
||||
var boundResult = result.Bind(s =>
|
||||
s.Length > 3 ? Result<int, string>.Success(s.Length) : Result<int, string>.Failure("Length too small"));
|
||||
|
||||
// Assert
|
||||
Assert.That(boundResult.IsFailure, Is.True);
|
||||
Assert.That(boundResult.ErrorValue, Is.EqualTo("Length too small"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试MapError方法 - 验证Failure错误值能正确映射
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Result_MapError_Should_Transform_Failure_Error()
|
||||
{
|
||||
// Arrange
|
||||
var result = Result<string, string>.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"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试MapError方法 - 验证Success映射错误后仍保持Success状态
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Result_MapError_Should_Keep_Success_For_Success()
|
||||
{
|
||||
// Arrange
|
||||
var result = Result<string, string>.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"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试Match方法 - 验证Success值执行onSuccess分支
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Result_Match_Should_Execute_OnSuccess_Branch_For_Success()
|
||||
{
|
||||
// Arrange
|
||||
var result = Result<string, string>.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"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试Match方法 - 验证Failure值执行onFailure分支
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Result_Match_Should_Execute_OnFailure_Branch_For_Failure()
|
||||
{
|
||||
// Arrange
|
||||
var result = Result<string, string>.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"));
|
||||
}
|
||||
}
|
||||
@ -1,108 +0,0 @@
|
||||
using GFramework.Core.functional.types;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GFramework.Core.Tests.functional.types;
|
||||
|
||||
/// <summary>
|
||||
/// Result类型测试类,用于验证Result类型的基本功能
|
||||
/// 包括创建Success和Failure实例、值访问等功能的测试
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class ResultTests
|
||||
{
|
||||
/// <summary>
|
||||
/// 测试创建Success实例 - 验证能正确创建成功结果
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Result_Success_Should_Create_With_Value()
|
||||
{
|
||||
// Arrange
|
||||
var value = "Success data";
|
||||
|
||||
// Act
|
||||
var result = Result<string, string>.Success(value);
|
||||
|
||||
// Assert
|
||||
Assert.That(result.IsSuccess, Is.True);
|
||||
Assert.That(result.IsFailure, Is.False);
|
||||
Assert.That(result.SuccessValue, Is.EqualTo(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试访问Success值 - 验证能正确获取成功值
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Result_Success_Value_Access_Should_Work()
|
||||
{
|
||||
// Arrange
|
||||
var result = Result<string, string>.Success("test");
|
||||
|
||||
// Act & Assert
|
||||
Assert.That(result.IsSuccess, Is.True);
|
||||
Assert.That(result.SuccessValue, Is.EqualTo("test"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试访问Success的错误值 - 验证在成功状态下访问错误值抛出异常
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Result_Success_Error_Access_Should_Throw_Exception()
|
||||
{
|
||||
// Arrange
|
||||
var result = Result<string, string>.Success("success");
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<InvalidOperationException>(() =>
|
||||
{
|
||||
var _ = result.ErrorValue;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试创建Failure实例 - 验证能正确创建失败结果
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Result_Failure_Should_Create_With_Error()
|
||||
{
|
||||
// Arrange
|
||||
var error = "Something went wrong";
|
||||
|
||||
// Act
|
||||
var result = Result<string, string>.Failure(error);
|
||||
|
||||
// Assert
|
||||
Assert.That(result.IsFailure, Is.True);
|
||||
Assert.That(result.IsSuccess, Is.False);
|
||||
Assert.That(result.ErrorValue, Is.EqualTo(error));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试访问Failure值 - 验证能正确获取错误值
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Result_Failure_Value_Access_Should_Work()
|
||||
{
|
||||
// Arrange
|
||||
var result = Result<string, string>.Failure("error");
|
||||
|
||||
// Act & Assert
|
||||
Assert.That(result.IsFailure, Is.True);
|
||||
Assert.That(result.ErrorValue, Is.EqualTo("error"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试访问Failure的成功值 - 验证在失败状态下访问成功值抛出异常
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Result_Failure_Success_Access_Should_Throw_Exception()
|
||||
{
|
||||
// Arrange
|
||||
var result = Result<string, string>.Failure("error");
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<InvalidOperationException>(() =>
|
||||
{
|
||||
var _ = result.SuccessValue;
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1,69 +0,0 @@
|
||||
using GFramework.Core.extensions;
|
||||
using GFramework.Core.functional.types;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GFramework.Core.Tests.functional.types;
|
||||
|
||||
/// <summary>
|
||||
/// TypeExtensions扩展方法测试类,用于验证类型转换相关扩展方法的正确性
|
||||
/// 包括安全类型转换和强制类型转换功能的测试
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class TypeExtensionsTests
|
||||
{
|
||||
#region As Tests
|
||||
|
||||
/// <summary>
|
||||
/// 测试As方法 - 验证安全类型转换功能
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void As_Should_Perform_Safe_Type_Cast()
|
||||
{
|
||||
// Arrange
|
||||
object obj = "Hello";
|
||||
|
||||
// Act
|
||||
var result = obj.As<string>();
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo("Hello"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试As方法 - 验证不兼容类型转换返回null
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void As_Should_Return_Null_For_Incompatible_Types()
|
||||
{
|
||||
// Arrange
|
||||
object obj = 42;
|
||||
|
||||
// Act
|
||||
var result = obj.As<string>();
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.Null);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cast Tests
|
||||
|
||||
/// <summary>
|
||||
/// 测试Cast方法 - 验证强制类型转换功能
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Cast_Should_Perform_Forced_Type_Cast()
|
||||
{
|
||||
// Arrange
|
||||
object obj = "Hello";
|
||||
|
||||
// Act
|
||||
var result = obj.Cast<string>();
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo("Hello"));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -9,4 +9,7 @@
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\$(AssemblyName).Abstractions\$(AssemblyName).Abstractions.csproj"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="LanguageExt.Core" Version="4.4.9"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@ -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;
|
||||
global using System.Threading.Tasks;
|
||||
global using LanguageExt.Common;
|
||||
global using LanguageExt.Effects;
|
||||
global using LanguageExt.Pretty;
|
||||
@ -235,7 +235,6 @@ public sealed class CoroutineScheduler(
|
||||
public int Clear()
|
||||
{
|
||||
var count = ActiveCoroutineCount;
|
||||
|
||||
Array.Clear(_slots);
|
||||
_metadata.Clear();
|
||||
_tagged.Clear();
|
||||
|
||||
@ -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<int, int> addTwo = x => x + 2;
|
||||
Func<int, int> multiplyByThree = x => x * 3;
|
||||
var composed = addTwo.Then(multiplyByThree); // 先+2再*3
|
||||
var result = composed(5); // (5+2)*3 = 21
|
||||
```
|
||||
|
||||
- **After** - 反向函数组合
|
||||
```csharp
|
||||
// 与Then相反,以不同的顺序组合函数
|
||||
Func<int, int> multiplyByThree = x => x * 3;
|
||||
Func<int, int> 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<int, int> 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<int, int, int> add = (x, y) => x + y;
|
||||
var curriedAdd = add.Curry(); // 返回 Func<int, Func<int, int>>
|
||||
var addFive = curriedAdd(5); // 返回 Func<int, int>
|
||||
var result = addFive(3); // 8
|
||||
```
|
||||
|
||||
- **Uncurry** - 取消柯里化
|
||||
```csharp
|
||||
// 将柯里化函数转换回多参数函数
|
||||
var curriedAdd = ((Func<int, int, int>)((x, y) => x + y)).Curry();
|
||||
var uncurriedAdd = curriedAdd.Uncurry(); // 返回 Func<int, int, int>
|
||||
var result = uncurriedAdd(5, 3); // 8
|
||||
```
|
||||
|
||||
- **Partial** - 部分应用
|
||||
```csharp
|
||||
// 固定函数的部分参数
|
||||
Func<int, int, int> 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<int, int> 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<string>(); // "Hello"
|
||||
var incompatible = obj.As<int>(); // null
|
||||
```
|
||||
|
||||
- **Cast** - 强制类型转换
|
||||
```csharp
|
||||
// 强制类型转换,失败时抛出异常
|
||||
object obj = "Hello";
|
||||
var str = obj.Cast<string>(); // "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<int, int> addTwo = x => x + 2;
|
||||
Func<int, int> square = x => x * x;
|
||||
Func<int, int> 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方法返回元组,便于处理可能发生的异常
|
||||
- 柯里化和部分应用有助于创建更灵活的函数
|
||||
- 链式操作可以提高代码可读性,但要注意性能影响
|
||||
|
||||
## 适用场景
|
||||
|
||||
- 数据转换和处理管道
|
||||
- 函数组合和复用
|
||||
- 避免中间变量的创建
|
||||
- 提高代码的声明式风格
|
||||
- 创建可重用的功能组件
|
||||
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// 提供集合的函数式编程扩展方法
|
||||
/// </summary>
|
||||
public static class EnumerableExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Map:对集合中的每个元素应用函数
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">源集合元素的类型</typeparam>
|
||||
/// <typeparam name="TResult">映射后集合元素的类型</typeparam>
|
||||
/// <param name="source">要映射的源集合</param>
|
||||
/// <param name="selector">用于转换元素的函数</param>
|
||||
/// <returns>映射后的元素序列</returns>
|
||||
public static IEnumerable<TResult> Map<TSource, TResult>(
|
||||
this IEnumerable<TSource> source,
|
||||
Func<TSource, TResult> selector)
|
||||
=> source.Select(selector);
|
||||
|
||||
/// <summary>
|
||||
/// Filter:过滤集合
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">集合元素的类型</typeparam>
|
||||
/// <param name="source">要过滤的源集合</param>
|
||||
/// <param name="predicate">用于确定是否包含元素的条件函数</param>
|
||||
/// <returns>满足条件的元素序列</returns>
|
||||
public static IEnumerable<TSource> Filter<TSource>(
|
||||
this IEnumerable<TSource> source,
|
||||
Func<TSource, bool> predicate)
|
||||
=> source.Where(predicate);
|
||||
|
||||
/// <summary>
|
||||
/// Reduce:将集合归约为单个值
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">集合元素的类型</typeparam>
|
||||
/// <typeparam name="TResult">归约结果的类型</typeparam>
|
||||
/// <param name="source">要归约的源集合</param>
|
||||
/// <param name="seed">初始累加值</param>
|
||||
/// <param name="accumulator">累加器函数</param>
|
||||
/// <returns>归约后的最终值</returns>
|
||||
public static TResult Reduce<TSource, TResult>(
|
||||
this IEnumerable<TSource> source,
|
||||
TResult seed,
|
||||
Func<TResult, TSource, TResult> accumulator)
|
||||
=> source.Aggregate(seed, accumulator);
|
||||
}
|
||||
@ -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;
|
||||
|
||||
/// <summary>
|
||||
@ -20,82 +18,6 @@ namespace GFramework.Core.functional.control;
|
||||
/// </summary>
|
||||
public static class ControlExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Match:模式匹配(类似switch表达式)
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">输入值的类型</typeparam>
|
||||
/// <typeparam name="TResult">匹配结果的类型</typeparam>
|
||||
/// <param name="value">要进行模式匹配的输入值</param>
|
||||
/// <param name="cases">匹配案例数组,每个包含谓词和处理器</param>
|
||||
/// <returns>匹配到的处理结果</returns>
|
||||
/// <exception cref="InvalidOperationException">当没有匹配的案例时抛出</exception>
|
||||
public static Option<TResult> Match<TSource, TResult>(
|
||||
this TSource value,
|
||||
params (Func<TSource, bool> predicate, Func<TSource, TResult> handler)[] cases)
|
||||
{
|
||||
foreach (var (predicate, handler) in cases)
|
||||
{
|
||||
if (predicate(value))
|
||||
return Option<TResult>.Some(handler(value));
|
||||
}
|
||||
|
||||
return Option<TResult>.None();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// MatchOrDefault:带默认值的模式匹配
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">输入值的类型</typeparam>
|
||||
/// <typeparam name="TResult">匹配结果的类型</typeparam>
|
||||
/// <param name="value">要进行模式匹配的输入值</param>
|
||||
/// <param name="defaultValue">当没有匹配案例时的默认返回值</param>
|
||||
/// <param name="cases">匹配案例数组,每个包含谓词和处理器</param>
|
||||
/// <returns>匹配到的处理结果或默认值</returns>
|
||||
public static TResult MatchOrDefault<TSource, TResult>(
|
||||
this TSource value,
|
||||
TResult defaultValue,
|
||||
params (Func<TSource, bool> predicate, Func<TSource, TResult> handler)[] cases)
|
||||
{
|
||||
foreach (var (predicate, handler) in cases)
|
||||
{
|
||||
if (predicate(value))
|
||||
return handler(value);
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If:条件执行
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">输入值的类型</typeparam>
|
||||
/// <param name="value">要进行条件判断的输入值</param>
|
||||
/// <param name="predicate">条件判断函数</param>
|
||||
/// <param name="thenFunc">条件为真时执行的转换函数</param>
|
||||
/// <returns>条件为真时返回转换后的值,否则返回原值</returns>
|
||||
public static TSource If<TSource>(
|
||||
this TSource value,
|
||||
Func<TSource, bool> predicate,
|
||||
Func<TSource, TSource> thenFunc)
|
||||
=> predicate(value) ? thenFunc(value) : value;
|
||||
|
||||
/// <summary>
|
||||
/// IfElse:条件分支
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">输入值的类型</typeparam>
|
||||
/// <param name="value">要进行条件判断的输入值</param>
|
||||
/// <param name="predicate">条件判断函数</param>
|
||||
/// <param name="thenFunc">条件为真时执行的转换函数</param>
|
||||
/// <param name="elseFunc">条件为假时执行的转换函数</param>
|
||||
/// <returns>根据条件返回相应的转换结果</returns>
|
||||
public static TSource IfElse<TSource>(
|
||||
this TSource value,
|
||||
Func<TSource, bool> predicate,
|
||||
Func<TSource, TSource> thenFunc,
|
||||
Func<TSource, TSource> elseFunc)
|
||||
=> predicate(value) ? thenFunc(value) : elseFunc(value);
|
||||
|
||||
/// <summary>
|
||||
/// TakeIf:条件返回值或null
|
||||
/// </summary>
|
||||
|
||||
@ -20,42 +20,23 @@ namespace GFramework.Core.functional.functions;
|
||||
/// </summary>
|
||||
public static class FunctionExtensions
|
||||
{
|
||||
#region 部分应用 - Partial
|
||||
#region Repeat
|
||||
|
||||
/// <summary>
|
||||
/// Partial:部分应用函数(固定第一个参数)
|
||||
/// Repeat:对值重复应用函数 n 次
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">第一个参数的类型</typeparam>
|
||||
/// <typeparam name="T2">第二个参数的类型</typeparam>
|
||||
/// <typeparam name="TResult">函数返回结果的类型</typeparam>
|
||||
/// <param name="func">要部分应用的二参数函数</param>
|
||||
/// <param name="firstArg">要固定的第一个参数值</param>
|
||||
/// <returns>部分应用后的函数,只接受第二个参数</returns>
|
||||
public static Func<T2, TResult> Partial<T1, T2, TResult>(
|
||||
this Func<T1, T2, TResult> func,
|
||||
T1 firstArg)
|
||||
=> x => func(firstArg, x);
|
||||
|
||||
#endregion
|
||||
|
||||
#region 重复执行 - Repeat
|
||||
|
||||
/// <summary>
|
||||
/// Repeat:重复执行函数n次
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">输入值的类型</typeparam>
|
||||
/// <param name="value">初始输入值</param>
|
||||
/// <param name="times">重复执行的次数</param>
|
||||
/// <param name="func">要重复执行的函数</param>
|
||||
/// <returns>经过多次变换后的最终值</returns>
|
||||
public static TSource Repeat<TSource>(
|
||||
this TSource value,
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// 当 times 小于 0 时抛出
|
||||
/// </exception>
|
||||
public static T Repeat<T>(
|
||||
this T value,
|
||||
int times,
|
||||
Func<TSource, TSource> func)
|
||||
Func<T, T> 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
|
||||
|
||||
/// <summary>
|
||||
/// Try:安全执行,捕获异常
|
||||
/// Try:安全执行并返回 language-ext 的 Result
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">输入值的类型</typeparam>
|
||||
/// <typeparam name="TResult">函数返回结果的类型</typeparam>
|
||||
/// <param name="value">要传递给函数的输入值</param>
|
||||
/// <param name="func">要安全执行的函数</param>
|
||||
/// <returns>包含执行状态、结果和错误信息的元组</returns>
|
||||
public static (bool success, TResult? result, Exception? error) Try<TSource, TResult>(
|
||||
public static Result<TResult> Try<TSource, TResult>(
|
||||
this TSource value,
|
||||
Func<TSource, TResult> func)
|
||||
{
|
||||
try
|
||||
{
|
||||
return (true, func(value), null);
|
||||
return new Result<TResult>(func(value));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (false, default, ex);
|
||||
return new Result<TResult>(ex);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 缓存 - Memoize
|
||||
#region Memoize (Unbounded / Unsafe)
|
||||
|
||||
/// <summary>
|
||||
/// Memoize:缓存函数结果(线程安全版本)
|
||||
/// MemoizeUnbounded:
|
||||
/// 对函数结果进行无界缓存(线程安全)
|
||||
///
|
||||
/// ⚠ 注意:
|
||||
/// - 缓存永不释放
|
||||
/// - TSource 必须具有稳定的 Equals / GetHashCode
|
||||
/// - 仅适用于纯函数
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">函数输入参数的类型</typeparam>
|
||||
/// <typeparam name="TResult">函数返回结果的类型</typeparam>
|
||||
/// <param name="func">要缓存结果的函数</param>
|
||||
/// <returns>带有缓存功能的包装函数</returns>
|
||||
/// <remarks>
|
||||
/// 此版本使用ConcurrentDictionary确保线程安全。
|
||||
/// GetOrAdd是原子操作,可以安全地在多线程环境中使用。
|
||||
/// </remarks>
|
||||
public static Func<TSource, TResult> Memoize<TSource, TResult>(
|
||||
public static Func<TSource, TResult> MemoizeUnbounded<TSource, TResult>(
|
||||
this Func<TSource, TResult> func)
|
||||
where TSource : notnull
|
||||
{
|
||||
var cache = new ConcurrentDictionary<TSource, TResult>();
|
||||
return x => cache.GetOrAdd(x, func);
|
||||
return key => cache.GetOrAdd(key, func);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 映射 - Map
|
||||
#region Partial (Advanced)
|
||||
|
||||
/// <summary>
|
||||
/// Map:对单个对象应用函数
|
||||
/// Partial:部分应用(二参数函数固定第一个参数)
|
||||
///
|
||||
/// ⚠ 偏函数应用属于高级用法,不建议在业务代码滥用
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">源对象类型</typeparam>
|
||||
/// <typeparam name="TResult">映射后的类型</typeparam>
|
||||
/// <param name="source">要映射的源对象</param>
|
||||
/// <param name="selector">转换函数</param>
|
||||
/// <returns>映射后的对象</returns>
|
||||
public static TResult Map<TSource, TResult>(
|
||||
this TSource source,
|
||||
Func<TSource, TResult> selector)
|
||||
=> selector(source);
|
||||
|
||||
#endregion
|
||||
|
||||
#region 柯里化 - Curry/Uncurry
|
||||
|
||||
/// <summary>
|
||||
/// Curry:将二参数函数转换为柯里化形式
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">第一个参数的类型</typeparam>
|
||||
/// <typeparam name="T2">第二个参数的类型</typeparam>
|
||||
/// <typeparam name="TResult">函数返回结果的类型</typeparam>
|
||||
/// <param name="func">要柯里化的二参数函数</param>
|
||||
/// <returns>柯里化后的函数,接受一个参数并返回另一个函数</returns>
|
||||
public static Func<T1, Func<T2, TResult>> Curry<T1, T2, TResult>(
|
||||
this Func<T1, T2, TResult> func)
|
||||
=> x => y => func(x, y);
|
||||
|
||||
/// <summary>
|
||||
/// Uncurry:将柯里化函数转换回二参数函数
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">第一个参数的类型</typeparam>
|
||||
/// <typeparam name="T2">第二个参数的类型</typeparam>
|
||||
/// <typeparam name="TResult">函数返回结果的类型</typeparam>
|
||||
/// <param name="func">要取消柯里化的函数</param>
|
||||
/// <returns>恢复为二参数的函数</returns>
|
||||
public static Func<T1, T2, TResult> Uncurry<T1, T2, TResult>(
|
||||
this Func<T1, Func<T2, TResult>> func)
|
||||
=> (x, y) => func(x)(y);
|
||||
public static Func<T2, TResult> Partial<T1, T2, TResult>(
|
||||
this Func<T1, T2, TResult> func,
|
||||
T1 firstArg)
|
||||
=> second => func(firstArg, second);
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -19,71 +19,16 @@ namespace GFramework.Core.functional.pipe;
|
||||
public static class PipeExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Pipe:把值送进函数(value.Pipe(func))
|
||||
/// Also:
|
||||
/// 对值执行副作用操作并返回原值
|
||||
///
|
||||
/// 适用于日志、调试、状态同步等场景
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">输入值的类型</typeparam>
|
||||
/// <typeparam name="TResult">函数返回结果的类型</typeparam>
|
||||
/// <param name="value">要传递给函数的输入值</param>
|
||||
/// <param name="func">接收输入值并返回结果的函数</param>
|
||||
/// <returns>函数执行后的结果</returns>
|
||||
public static TResult Pipe<TSource, TResult>(
|
||||
this TSource value,
|
||||
Func<TSource, TResult> func)
|
||||
=> func(value);
|
||||
|
||||
/// <summary>
|
||||
/// Compose:函数组合(f1.Then(f2))
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">第一个函数的输入类型</typeparam>
|
||||
/// <typeparam name="TMiddle">第一个函数的输出类型,也是第二个函数的输入类型</typeparam>
|
||||
/// <typeparam name="TResult">第二个函数的输出类型</typeparam>
|
||||
/// <param name="first">第一个要执行的函数</param>
|
||||
/// <param name="second">第二个要执行的函数</param>
|
||||
/// <returns>组合后的新函数,先执行first再执行second</returns>
|
||||
public static Func<TSource, TResult> Then<TSource, TMiddle, TResult>(
|
||||
this Func<TSource, TMiddle> first,
|
||||
Func<TMiddle, TResult> second)
|
||||
=> x => second(first(x));
|
||||
|
||||
/// <summary>
|
||||
/// Compose:反向组合(f2.After(f1))
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">第一个函数的输入类型</typeparam>
|
||||
/// <typeparam name="TMiddle">第一个函数的输出类型,也是第二个函数的输入类型</typeparam>
|
||||
/// <typeparam name="TResult">第二个函数的输出类型</typeparam>
|
||||
/// <param name="second">第二个要执行的函数</param>
|
||||
/// <param name="first">第一个要执行的函数</param>
|
||||
/// <returns>组合后的新函数,先执行first再执行second</returns>
|
||||
public static Func<TSource, TResult> After<TSource, TMiddle, TResult>(
|
||||
this Func<TMiddle, TResult> second,
|
||||
Func<TSource, TMiddle> first)
|
||||
=> x => second(first(x));
|
||||
|
||||
/// <summary>
|
||||
/// Also:执行操作并返回原值
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">输入值的类型</typeparam>
|
||||
/// <param name="value">要执行操作的输入值</param>
|
||||
/// <param name="action">要执行的操作</param>
|
||||
/// <returns>原始输入值</returns>
|
||||
public static TSource Also<TSource>(
|
||||
this TSource value,
|
||||
Action<TSource> action)
|
||||
public static T Also<T>(
|
||||
this T value,
|
||||
Action<T> action)
|
||||
{
|
||||
action(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Let:将值转换为另一个值
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">输入值的类型</typeparam>
|
||||
/// <typeparam name="TResult">转换结果的类型</typeparam>
|
||||
/// <param name="value">要进行转换的输入值</param>
|
||||
/// <param name="transform">用于转换值的函数</param>
|
||||
/// <returns>转换后的结果</returns>
|
||||
public static TResult Let<TSource, TResult>(
|
||||
this TSource value,
|
||||
Func<TSource, TResult> transform)
|
||||
=> transform(value);
|
||||
}
|
||||
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// 提供Nullable类型转换为Option类型的扩展方法
|
||||
/// </summary>
|
||||
public static class NullableExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 将可空引用类型转换为Option类型
|
||||
/// </summary>
|
||||
/// <typeparam name="T">引用类型</typeparam>
|
||||
/// <param name="value">可空的引用类型值</param>
|
||||
/// <returns>如果值为null则返回None,否则返回包含该值的Some</returns>
|
||||
public static Option<T> ToOption<T>(this T? value)
|
||||
where T : class
|
||||
=> value is null
|
||||
? Option<T>.None()
|
||||
: Option<T>.Some(value);
|
||||
|
||||
/// <summary>
|
||||
/// 将可空值类型转换为Option类型
|
||||
/// </summary>
|
||||
/// <typeparam name="T">值类型</typeparam>
|
||||
/// <param name="value">可空的值类型值</param>
|
||||
/// <returns>如果值有值则返回包含该值的Some,否则返回None</returns>
|
||||
public static Option<T> ToOption<T>(this T? value)
|
||||
where T : struct
|
||||
=> value.HasValue
|
||||
? Option<T>.Some(value.Value)
|
||||
: Option<T>.None();
|
||||
}
|
||||
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// 表示一个可能存在也可能不存在的值
|
||||
/// </summary>
|
||||
public readonly struct Option<T>
|
||||
{
|
||||
private readonly T _value;
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前Option是否包含值
|
||||
/// </summary>
|
||||
public bool IsSome { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前Option是否为空值
|
||||
/// </summary>
|
||||
public bool IsNone => !IsSome;
|
||||
|
||||
/// <summary>
|
||||
/// 使用指定值创建Option实例
|
||||
/// </summary>
|
||||
/// <param name="value">要包装的值</param>
|
||||
private Option(T value)
|
||||
{
|
||||
_value = value;
|
||||
IsSome = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建空的Option实例
|
||||
/// </summary>
|
||||
/// <param name="_">占位参数,用于区分构造函数重载</param>
|
||||
private Option(bool _)
|
||||
{
|
||||
_value = default!;
|
||||
IsSome = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建包含指定值的Option实例
|
||||
/// </summary>
|
||||
/// <param name="value">要包装的值,不能为null</param>
|
||||
/// <returns>包含指定值的Option实例</returns>
|
||||
/// <exception cref="ArgumentNullException">当value为null时抛出</exception>
|
||||
public static Option<T> Some(T value)
|
||||
{
|
||||
return value is null ? throw new ArgumentNullException(nameof(value)) : new Option<T>(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建空的Option实例
|
||||
/// </summary>
|
||||
/// <returns>空的Option实例</returns>
|
||||
public static Option<T> None() => new(false);
|
||||
|
||||
/// <summary>
|
||||
/// 获取Option中包含的值
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">当Option为空时抛出</exception>
|
||||
public T Value =>
|
||||
IsSome
|
||||
? _value
|
||||
: throw new InvalidOperationException("Option has no value");
|
||||
}
|
||||
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// 提供Option类型的功能扩展方法,支持映射、绑定、过滤和匹配操作
|
||||
/// </summary>
|
||||
public static class OptionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 将Option中的值通过指定的映射函数转换为另一种类型的Option
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">源Option中值的类型</typeparam>
|
||||
/// <typeparam name="TResult">映射后结果的类型</typeparam>
|
||||
/// <param name="option">要进行映射操作的Option实例</param>
|
||||
/// <param name="mapper">用于将源值转换为目标值的映射函数</param>
|
||||
/// <returns>包含映射后值的新Option实例,如果原Option为空则返回None</returns>
|
||||
public static Option<TResult> Map<TSource, TResult>(
|
||||
this Option<TSource> option,
|
||||
Func<TSource, TResult> mapper)
|
||||
{
|
||||
return option.IsSome
|
||||
? Option<TResult>.Some(mapper(option.Value))
|
||||
: Option<TResult>.None();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将Option中的值通过指定的绑定函数转换为另一个Option,实现Option的扁平化映射
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">源Option中值的类型</typeparam>
|
||||
/// <typeparam name="TResult">绑定后Option中值的类型</typeparam>
|
||||
/// <param name="option">要进行绑定操作的Option实例</param>
|
||||
/// <param name="binder">用于将源值转换为新Option的绑定函数</param>
|
||||
/// <returns>绑定函数返回的Option实例,如果原Option为空则返回None</returns>
|
||||
public static Option<TResult> Bind<TSource, TResult>(
|
||||
this Option<TSource> option,
|
||||
Func<TSource, Option<TResult>> binder)
|
||||
{
|
||||
return option.IsSome
|
||||
? binder(option.Value)
|
||||
: Option<TResult>.None();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据指定的谓词函数过滤Option中的值
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">Option中值的类型</typeparam>
|
||||
/// <param name="option">要进行过滤操作的Option实例</param>
|
||||
/// <param name="predicate">用于判断值是否满足条件的谓词函数</param>
|
||||
/// <returns>如果Option有值且满足谓词条件则返回原Option,否则返回None</returns>
|
||||
public static Option<TSource> Filter<TSource>(
|
||||
this Option<TSource> option,
|
||||
Func<TSource, bool> predicate)
|
||||
{
|
||||
return option.IsSome && predicate(option.Value)
|
||||
? option
|
||||
: Option<TSource>.None();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 对Option进行模式匹配,根据Option的状态执行不同的函数
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">Option中值的类型</typeparam>
|
||||
/// <typeparam name="TResult">匹配结果的类型</typeparam>
|
||||
/// <param name="option">要进行匹配操作的Option实例</param>
|
||||
/// <param name="some">当Option包含值时执行的函数</param>
|
||||
/// <param name="none">当Option为空时执行的函数</param>
|
||||
/// <returns>根据Option状态执行相应函数后的结果</returns>
|
||||
public static TResult Match<TSource, TResult>(
|
||||
this Option<TSource> option,
|
||||
Func<TSource, TResult> some,
|
||||
Func<TResult> none)
|
||||
{
|
||||
return option.IsSome
|
||||
? some(option.Value)
|
||||
: none();
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// 提供Option类型值的操作扩展方法
|
||||
/// </summary>
|
||||
public static class OptionValueExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取Option中的值,如果Option为空则返回默认值
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Option中存储的值的类型</typeparam>
|
||||
/// <param name="option">要获取值的Option对象</param>
|
||||
/// <param name="defaultValue">当Option为空时返回的默认值</param>
|
||||
/// <returns>Option中的值或默认值</returns>
|
||||
public static T GetOrElse<T>(
|
||||
this Option<T> option,
|
||||
T defaultValue)
|
||||
=> option.IsSome ? option.Value : defaultValue;
|
||||
|
||||
/// <summary>
|
||||
/// 获取Option中的值,如果Option为空则通过工厂函数生成默认值
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Option中存储的值的类型</typeparam>
|
||||
/// <param name="option">要获取值的Option对象</param>
|
||||
/// <param name="defaultFactory">当Option为空时用于生成默认值的工厂函数</param>
|
||||
/// <returns>Option中的值或通过工厂函数生成的值</returns>
|
||||
public static T GetOrElse<T>(
|
||||
this Option<T> option,
|
||||
Func<T> defaultFactory)
|
||||
=> option.IsSome ? option.Value : defaultFactory();
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前Option,如果当前Option为空则返回备用Option
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Option中存储的值的类型</typeparam>
|
||||
/// <param name="option">当前Option对象</param>
|
||||
/// <param name="fallback">当当前Option为空时返回的备用Option</param>
|
||||
/// <returns>当前Option或备用Option</returns>
|
||||
public static Option<T> OrElse<T>(
|
||||
this Option<T> option,
|
||||
Option<T> fallback)
|
||||
=> option.IsSome ? option : fallback;
|
||||
}
|
||||
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// 表示一个可能成功也可能失败的计算结果
|
||||
/// </summary>
|
||||
/// <typeparam name="TSuccess">成功值的类型</typeparam>
|
||||
/// <typeparam name="TError">错误值的类型</typeparam>
|
||||
public readonly struct Result<TSuccess, TError>
|
||||
{
|
||||
private readonly TSuccess _success;
|
||||
private readonly TError _error;
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前结果是否为成功状态
|
||||
/// </summary>
|
||||
public bool IsSuccess { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前结果是否为失败状态
|
||||
/// </summary>
|
||||
public bool IsFailure => !IsSuccess;
|
||||
|
||||
/// <summary>
|
||||
/// 使用成功值初始化Result实例
|
||||
/// </summary>
|
||||
/// <param name="success">成功值</param>
|
||||
private Result(TSuccess success)
|
||||
{
|
||||
_success = success;
|
||||
_error = default!;
|
||||
IsSuccess = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用错误值初始化Result实例
|
||||
/// </summary>
|
||||
/// <param name="error">错误值</param>
|
||||
private Result(TError error)
|
||||
{
|
||||
_error = error;
|
||||
_success = default!;
|
||||
IsSuccess = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个表示成功的Result实例
|
||||
/// </summary>
|
||||
/// <param name="value">成功值</param>
|
||||
/// <returns>包含成功值的Result实例</returns>
|
||||
public static Result<TSuccess, TError> Success(TSuccess value)
|
||||
=> new(value);
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个表示失败的Result实例
|
||||
/// </summary>
|
||||
/// <param name="error">错误值</param>
|
||||
/// <returns>包含错误值的Result实例</returns>
|
||||
public static Result<TSuccess, TError> Failure(TError error)
|
||||
=> new(error);
|
||||
|
||||
/// <summary>
|
||||
/// 获取成功值,如果结果为失败则抛出异常
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">当结果为失败时抛出</exception>
|
||||
public TSuccess SuccessValue =>
|
||||
IsSuccess
|
||||
? _success
|
||||
: throw new InvalidOperationException("Result is Failure");
|
||||
|
||||
/// <summary>
|
||||
/// 获取错误值,如果结果为成功则抛出异常
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">当结果为成功时抛出</exception>
|
||||
public TError ErrorValue =>
|
||||
IsFailure
|
||||
? _error
|
||||
: throw new InvalidOperationException("Result is Success");
|
||||
}
|
||||
@ -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<TResult, TError> Map<TSuccess, TResult, TError>(
|
||||
this Result<TSuccess, TError> result,
|
||||
Func<TSuccess, TResult> mapper)
|
||||
{
|
||||
return result.IsSuccess
|
||||
? Result<TResult, TError>.Success(mapper(result.SuccessValue))
|
||||
: Result<TResult, TError>.Failure(result.ErrorValue);
|
||||
}
|
||||
|
||||
public static Result<TResult, TError> Bind<TSuccess, TResult, TError>(
|
||||
this Result<TSuccess, TError> result,
|
||||
Func<TSuccess, Result<TResult, TError>> binder)
|
||||
{
|
||||
return result.IsSuccess
|
||||
? binder(result.SuccessValue)
|
||||
: Result<TResult, TError>.Failure(result.ErrorValue);
|
||||
}
|
||||
|
||||
public static Result<TSuccess, TNewError> MapError<TSuccess, TError, TNewError>(
|
||||
this Result<TSuccess, TError> result,
|
||||
Func<TError, TNewError> mapper)
|
||||
{
|
||||
return result.IsFailure
|
||||
? Result<TSuccess, TNewError>.Failure(mapper(result.ErrorValue))
|
||||
: Result<TSuccess, TNewError>.Success(result.SuccessValue);
|
||||
}
|
||||
|
||||
public static TResult Match<TSuccess, TError, TResult>(
|
||||
this Result<TSuccess, TError> result,
|
||||
Func<TSuccess, TResult> onSuccess,
|
||||
Func<TError, TResult> onFailure)
|
||||
{
|
||||
return result.IsSuccess
|
||||
? onSuccess(result.SuccessValue)
|
||||
: onFailure(result.ErrorValue);
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// 提供类型转换相关的扩展方法
|
||||
/// </summary>
|
||||
public static class TypeExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 安全类型转换方法,将源类型转换为目标类型
|
||||
/// 如果转换失败或值为null,则返回null而不抛出异常
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">源类型参数</typeparam>
|
||||
/// <typeparam name="TResult">目标类型参数,必须为引用类型</typeparam>
|
||||
/// <param name="value">需要进行类型转换的源值</param>
|
||||
/// <returns>转换成功时返回目标类型实例,失败时返回null</returns>
|
||||
public static TResult? As<TSource, TResult>(
|
||||
this TSource value)
|
||||
where TResult : class
|
||||
=> value as TResult;
|
||||
|
||||
/// <summary>
|
||||
/// 强制类型转换方法,将对象转换为指定的目标类型
|
||||
/// 转换失败时会抛出InvalidCastException异常
|
||||
/// </summary>
|
||||
/// <typeparam name="TResult">目标类型参数</typeparam>
|
||||
/// <param name="value">需要进行强制类型转换的对象</param>
|
||||
/// <returns>转换后的目标类型实例</returns>
|
||||
/// <exception cref="InvalidCastException">当转换失败时抛出此异常</exception>
|
||||
public static TResult Cast<TResult>(
|
||||
this object value)
|
||||
=> (TResult)value;
|
||||
}
|
||||
@ -11,6 +11,7 @@
|
||||
<ProjectReference Include="..\$(AssemblyName).Abstractions\$(AssemblyName).Abstractions.csproj"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="LanguageExt.Core" Version="4.4.9"/>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@ -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;
|
||||
global using System.Threading.Tasks;
|
||||
global using LanguageExt.Common;
|
||||
global using LanguageExt.Effects;
|
||||
global using LanguageExt.Pretty;
|
||||
@ -11,6 +11,7 @@
|
||||
<PackageReference Include="Godot.SourceGenerators" Version="4.6.0" PrivateAssets="all"/>
|
||||
<PackageReference Include="GodotSharp" Version="4.6.0"/>
|
||||
<PackageReference Include="GodotSharpEditor" Version="4.6.0" PrivateAssets="all"/>
|
||||
<PackageReference Include="LanguageExt.Core" Version="4.4.9"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@ -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;
|
||||
global using System.Threading.Tasks;
|
||||
global using LanguageExt.Common;
|
||||
global using LanguageExt.Effects;
|
||||
global using LanguageExt.Pretty;
|
||||
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user