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:
GeWuYou 2026-01-31 22:31:50 +08:00
parent 3493d6a481
commit b2e8ed9787
31 changed files with 73 additions and 2428 deletions

View File

@ -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
}

View File

@ -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>
@ -189,10 +41,6 @@ public class ControlExtensionsTests
Assert.That(result, Is.Null);
}
#endregion
#region TakeUnless Tests
/// <summary>
/// 测试TakeUnless方法 - 验证条件为假时返回原值
/// </summary>
@ -224,6 +72,4 @@ public class ControlExtensionsTests
// Assert
Assert.That(result, Is.Null);
}
#endregion
}

View File

@ -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>
@ -73,10 +27,6 @@ public class FunctionExtensionsTests
Assert.That(result, Is.EqualTo(10));
}
#endregion
#region Repeat Tests
/// <summary>
/// 测试Repeat方法 - 验证重复执行函数功能
/// </summary>
@ -93,80 +43,4 @@ public class FunctionExtensionsTests
// 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
}

View File

@ -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));
}
}

View File

@ -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);
}
}

View File

@ -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"));
}
}

View File

@ -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;
});
}
}

View File

@ -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);
}
}

View File

@ -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"));
}
}

View File

@ -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;
});
}
}

View File

@ -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
}

View File

@ -9,4 +9,7 @@
<ItemGroup>
<ProjectReference Include="..\$(AssemblyName).Abstractions\$(AssemblyName).Abstractions.csproj"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="LanguageExt.Core" Version="4.4.9"/>
</ItemGroup>
</Project>

View File

@ -16,3 +16,6 @@ global using System.Collections.Generic;
global using System.Linq;
global using System.Threading;
global using System.Threading.Tasks;
global using LanguageExt.Common;
global using LanguageExt.Effects;
global using LanguageExt.Pretty;

View File

@ -235,7 +235,6 @@ public sealed class CoroutineScheduler(
public int Clear()
{
var count = ActiveCoroutineCount;
Array.Clear(_slots);
_metadata.Clear();
_tagged.Clear();

View File

@ -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&lt;T&gt;** - 表示可能包含值或不包含值的类型
```csharp
// 创建包含值的Option
var someValue = Option&lt;string&gt;.Some("Hello");
Console.WriteLine(someValue.IsSome); // True
Console.WriteLine(someValue.Value); // "Hello"
// 创建空的Option
var noValue = Option&lt;string&gt;.None();
Console.WriteLine(noValue.IsNone); // True
```
#### Option扩展方法
- **Map** - 对Option中的值进行映射转换
```csharp
var someValue = Option&lt;string&gt;.Some("hello");
var lengthOption = someValue.Map(s => s.Length); // Some(5)
var noneValue = Option&lt;string&gt;.None();
var noneLength = noneValue.Map(s => s.Length); // None
```
- **Bind** - 将Option中的值转换为另一个Option
```csharp
var someValue = Option&lt;string&gt;.Some("hello");
var result = someValue.Bind(s => s.Length > 3 ? Option&lt;int&gt;.Some(s.Length) : Option&lt;int&gt;.None()); // Some(5)
var shortValue = Option&lt;string&gt;.Some("hi");
var result2 = shortValue.Bind(s => s.Length > 3 ? Option&lt;int&gt;.Some(s.Length) : Option&lt;int&gt;.None()); // None
```
- **Filter** - 根据条件过滤Option中的值
```csharp
var someValue = Option&lt;string&gt;.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&lt;string&gt;.Some("hello");
var result = someValue.Match(
some: s => $"Value: {s}",
none: () => "No value"
); // "Value: hello"
var noneValue = Option&lt;string&gt;.None();
var result2 = noneValue.Match(
some: s => $"Value: {s}",
none: () => "No value"
); // "No value"
```
- **GetOrElse** - 获取值或返回默认值
```csharp
var someValue = Option&lt;string&gt;.Some("hello");
var value1 = someValue.GetOrElse("default"); // "hello"
var noneValue = Option&lt;string&gt;.None();
var value2 = noneValue.GetOrElse("default"); // "default"
```
- **OrElse** - 当前Option为空时返回备选Option
```csharp
var someValue = Option&lt;string&gt;.Some("primary");
var result1 = someValue.OrElse(Option&lt;string&gt;.Some("fallback")); // Some("primary")
var noneValue = Option&lt;string&gt;.None();
var result2 = noneValue.OrElse(Option&lt;string&gt;.Some("fallback")); // Some("fallback")
```
### 7. Result Type - 结果类型
位于 `GFramework.Core.functional.types` 命名空间,提供表示成功或失败结果的类型。
#### 核心类型及用法:
- **Result&lt;TSuccess, TError&gt;** - 表示可能成功或失败的计算结果
```csharp
// 创建成功的结果
var successResult = Result&lt;string, string&gt;.Success("Operation successful");
Console.WriteLine(successResult.IsSuccess); // True
Console.WriteLine(successResult.SuccessValue); // "Operation successful"
// 创建失败的结果
var failureResult = Result&lt;string, string&gt;.Failure("Operation failed");
Console.WriteLine(failureResult.IsFailure); // True
Console.WriteLine(failureResult.ErrorValue); // "Operation failed"
```
#### Result扩展方法
- **Map** - 对成功值进行映射转换
```csharp
var successResult = Result&lt;string, string&gt;.Success("hello");
var lengthResult = successResult.Map(s => s.Length); // Success(5)
var failureResult = Result&lt;string, string&gt;.Failure("error");
var lengthResult2 = failureResult.Map(s => s.Length); // Failure("error")
```
- **Bind** - 将成功值转换为另一个Result
```csharp
var successResult = Result&lt;string, string&gt;.Success("hello");
var result = successResult.Bind(s =>
s.Length > 3 ?
Result&lt;int, string&gt;.Success(s.Length) :
Result&lt;int, string&gt;.Failure("Length too small"));
// Result&lt;int, string&gt;.Success(5)
```
- **MapError** - 对错误值进行映射转换
```csharp
var failureResult = Result&lt;string, string&gt;.Failure("original error");
var mappedErrorResult = failureResult.MapError(err => $"Mapped: {err}");
// Result&lt;string, string&gt;.Failure("Mapped: original error")
```
- **Match** - 模式匹配Result的状态
```csharp
var successResult = Result&lt;string, string&gt;.Success("data");
var result = successResult.Match(
onSuccess: data => $"Success: {data}",
onFailure: error => $"Error: {error}"
); // "Success: data"
var failureResult = Result&lt;string, string&gt;.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方法返回元组便于处理可能发生的异常
- 柯里化和部分应用有助于创建更灵活的函数
- 链式操作可以提高代码可读性,但要注意性能影响
## 适用场景
- 数据转换和处理管道
- 函数组合和复用
- 避免中间变量的创建
- 提高代码的声明式风格
- 创建可重用的功能组件

View File

@ -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);
}

View File

@ -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>

View File

@ -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
}

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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");
}

View File

@ -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();
}
}

View File

@ -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;
}

View File

@ -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");
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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>

View File

@ -17,3 +17,6 @@ global using System.Collections.Concurrent;
global using System.Linq;
global using System.Threading;
global using System.Threading.Tasks;
global using LanguageExt.Common;
global using LanguageExt.Effects;
global using LanguageExt.Pretty;

View File

@ -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>

View File

@ -16,3 +16,6 @@ global using System.Collections.Generic;
global using System.Linq;
global using System.Threading;
global using System.Threading.Tasks;
global using LanguageExt.Common;
global using LanguageExt.Effects;
global using LanguageExt.Pretty;

View File

@ -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;