From b4c1096b10a2eccee43ea087c7253fbcf2731b87 Mon Sep 17 00:00:00 2001
From: GeWuYou <95328647+GeWuYou@users.noreply.github.com>
Date: Sat, 31 Jan 2026 09:06:10 +0800
Subject: [PATCH] =?UTF-8?q?feat(core):=20=E6=B7=BB=E5=8A=A0=E5=87=BD?=
=?UTF-8?q?=E6=95=B0=E5=BC=8F=E7=BC=96=E7=A8=8B=E7=AE=A1=E9=81=93=E6=89=A9?=
=?UTF-8?q?=E5=B1=95=E6=96=B9=E6=B3=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 实现 Pipe 方法用于将值传递给函数
- 添加 Then 和 After 方法用于函数组合操作
- 提供 Tap 和 Also 方法用于执行副作用操作
- 添加 Map、Filter、Reduce 方法用于集合操作
- 实现 Curry、Uncurry、Partial 方法支持柯里化
- 添加 Match 和 MatchOrDefault 方法用于模式匹配
- 提供 If、IfElse 条件执行功能
- 添加类型转换相关方法 As、Cast
- 实现 Let、TakeIf、TakeUnless 等 方法
- 添加 Repeat 方法用于重复执行函数
- 提供 Try 方法用于安全执行函数
- 实现 Memoize 方法用于函数结果缓存
---
.../functional/pipe/PipeExtensions.cs | 380 ++++++++++++++++++
1 file changed, 380 insertions(+)
create mode 100644 GFramework.Core/functional/pipe/PipeExtensions.cs
diff --git a/GFramework.Core/functional/pipe/PipeExtensions.cs b/GFramework.Core/functional/pipe/PipeExtensions.cs
new file mode 100644
index 0000000..3ce37ad
--- /dev/null
+++ b/GFramework.Core/functional/pipe/PipeExtensions.cs
@@ -0,0 +1,380 @@
+// 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.pipe;
+
+///
+/// 提供函数式编程中的管道和组合操作扩展方法
+///
+public static class PipeExtensions
+{
+ ///
+ /// Pipe:把值送进函数(value.Pipe(func))
+ ///
+ /// 输入值的类型
+ /// 函数返回结果的类型
+ /// 要传递给函数的输入值
+ /// 接收输入值并返回结果的函数
+ /// 函数执行后的结果
+ public static TResult Pipe(
+ this TSource value,
+ Func func)
+ => func(value);
+
+ ///
+ /// Compose:函数组合(f1.Then(f2))
+ ///
+ /// 第一个函数的输入类型
+ /// 第一个函数的输出类型,也是第二个函数的输入类型
+ /// 第二个函数的输出类型
+ /// 第一个要执行的函数
+ /// 第二个要执行的函数
+ /// 组合后的新函数,先执行first再执行second
+ public static Func Then(
+ this Func first,
+ Func second)
+ => x => second(first(x));
+
+ ///
+ /// Compose:反向组合(f2.After(f1))
+ ///
+ /// 第一个函数的输入类型
+ /// 第一个函数的输出类型,也是第二个函数的输入类型
+ /// 第二个函数的输出类型
+ /// 第二个要执行的函数
+ /// 第一个要执行的函数
+ /// 组合后的新函数,先执行first再执行second
+ public static Func After(
+ this Func second,
+ Func first)
+ => x => second(first(x));
+
+ ///
+ /// Tap:执行副作用操作但返回原值(用于调试、日志等)
+ ///
+ /// 输入值的类型
+ /// 要执行操作的输入值
+ /// 要执行的副作用操作
+ /// 原始输入值
+ public static TSource Tap(
+ this TSource value,
+ Action action)
+ {
+ action(value);
+ return value;
+ }
+
+ ///
+ /// Map:对集合中的每个元素应用函数
+ ///
+ /// 源集合元素的类型
+ /// 映射后集合元素的类型
+ /// 要映射的源集合
+ /// 用于转换元素的函数
+ /// 映射后的元素序列
+ public static IEnumerable Map(
+ this IEnumerable source,
+ Func selector)
+ => source.Select(selector);
+
+ ///
+ /// Filter:过滤集合
+ ///
+ /// 集合元素的类型
+ /// 要过滤的源集合
+ /// 用于确定是否包含元素的条件函数
+ /// 满足条件的元素序列
+ public static IEnumerable Filter(
+ this IEnumerable source,
+ Func predicate)
+ => source.Where(predicate);
+
+ ///
+ /// Reduce:将集合归约为单个值
+ ///
+ /// 集合元素的类型
+ /// 归约结果的类型
+ /// 要归约的源集合
+ /// 初始累加值
+ /// 累加器函数
+ /// 归约后的最终值
+ public static TResult Reduce(
+ this IEnumerable source,
+ TResult seed,
+ Func accumulator)
+ => source.Aggregate(seed, accumulator);
+
+ ///
+ /// Apply:将函数应用于值(柯里化辅助)
+ ///
+ /// 输入值的类型
+ /// 函数返回结果的类型
+ /// 要应用的函数
+ /// 要传递给函数的输入值
+ /// 函数执行后的结果
+ public static TResult Apply(
+ this Func func,
+ TSource value)
+ => func(value);
+
+ ///
+ /// Curry:将二参数函数转换为柯里化形式
+ ///
+ /// 第一个参数的类型
+ /// 第二个参数的类型
+ /// 函数返回结果的类型
+ /// 要柯里化的二参数函数
+ /// 柯里化后的函数,接受一个参数并返回另一个函数
+ public static Func> Curry(
+ this Func func)
+ => x => y => func(x, y);
+
+ ///
+ /// Uncurry:将柯里化函数转换回二参数函数
+ ///
+ /// 第一个参数的类型
+ /// 第二个参数的类型
+ /// 函数返回结果的类型
+ /// 要取消柯里化的函数
+ /// 恢复为二参数的函数
+ public static Func Uncurry(
+ this Func> func)
+ => (x, y) => func(x)(y);
+
+ ///
+ /// Partial:部分应用函数(固定第一个参数)
+ ///
+ /// 第一个参数的类型
+ /// 第二个参数的类型
+ /// 函数返回结果的类型
+ /// 要部分应用的二参数函数
+ /// 要固定的第一个参数值
+ /// 部分应用后的函数,只接受第二个参数
+ public static Func Partial(
+ this Func func,
+ T1 firstArg)
+ => x => func(firstArg, x);
+
+ ///
+ /// Match:模式匹配(类似switch表达式)
+ ///
+ /// 输入值的类型
+ /// 匹配结果的类型
+ /// 要进行模式匹配的输入值
+ /// 匹配案例数组,每个包含谓词和处理器
+ /// 匹配到的处理结果
+ /// 当没有匹配的案例时抛出
+ public static TResult Match(
+ this TSource value,
+ params (Func predicate, Func handler)[] cases)
+ {
+ foreach (var (predicate, handler) in cases)
+ {
+ if (predicate(value))
+ return handler(value);
+ }
+ throw new InvalidOperationException("No matching case found");
+ }
+
+ ///
+ /// MatchOrDefault:带默认值的模式匹配
+ ///
+ /// 输入值的类型
+ /// 匹配结果的类型
+ /// 要进行模式匹配的输入值
+ /// 当没有匹配案例时的默认返回值
+ /// 匹配案例数组,每个包含谓词和处理器
+ /// 匹配到的处理结果或默认值
+ public static TResult MatchOrDefault(
+ this TSource value,
+ TResult defaultValue,
+ params (Func predicate, Func handler)[] cases)
+ {
+ foreach (var (predicate, handler) in cases)
+ {
+ if (predicate(value))
+ return handler(value);
+ }
+ return defaultValue;
+ }
+
+ ///
+ /// If:条件执行
+ ///
+ /// 输入值的类型
+ /// 要进行条件判断的输入值
+ /// 条件判断函数
+ /// 条件为真时执行的转换函数
+ /// 条件为真时返回转换后的值,否则返回原值
+ public static TSource If(
+ this TSource value,
+ Func predicate,
+ Func thenFunc)
+ => predicate(value) ? thenFunc(value) : value;
+
+ ///
+ /// IfElse:条件分支
+ ///
+ /// 输入值的类型
+ /// 要进行条件判断的输入值
+ /// 条件判断函数
+ /// 条件为真时执行的转换函数
+ /// 条件为假时执行的转换函数
+ /// 根据条件返回相应的转换结果
+ public static TSource IfElse(
+ this TSource value,
+ Func predicate,
+ Func thenFunc,
+ Func elseFunc)
+ => predicate(value) ? thenFunc(value) : elseFunc(value);
+
+ ///
+ /// As:类型转换(安全转换)
+ ///
+ /// 源类型的泛型参数
+ /// 目标类型的泛型参数
+ /// 要进行类型转换的值
+ /// 转换后的值,如果转换失败则返回null
+ public static TResult? As(
+ this TSource value)
+ where TResult : class
+ => value as TResult;
+
+ ///
+ /// Cast:强制类型转换
+ ///
+ /// 目标类型的泛型参数
+ /// 要进行类型转换的对象
+ /// 强制转换后的值
+ public static TResult Cast(
+ this object value)
+ => (TResult)value;
+
+ ///
+ /// Also:执行操作并返回原值
+ ///
+ /// 输入值的类型
+ /// 要执行操作的输入值
+ /// 要执行的操作
+ /// 原始输入值
+ public static TSource Also(
+ this TSource value,
+ Action action)
+ {
+ action(value);
+ return value;
+ }
+
+ ///
+ /// Let:将值转换为另一个值
+ ///
+ /// 输入值的类型
+ /// 转换结果的类型
+ /// 要进行转换的输入值
+ /// 用于转换值的函数
+ /// 转换后的结果
+ public static TResult Let(
+ this TSource value,
+ Func transform)
+ => transform(value);
+
+ ///
+ /// TakeIf:条件返回值或null
+ ///
+ /// 输入值的类型
+ /// 要进行条件判断的输入值
+ /// 条件判断函数
+ /// 条件为真时返回原值,否则返回null
+ public static TSource? TakeIf(
+ this TSource value,
+ Func predicate)
+ where TSource : class
+ => predicate(value) ? value : null;
+
+ ///
+ /// TakeUnless:条件相反的TakeIf
+ ///
+ /// 输入值的类型
+ /// 要进行条件判断的输入值
+ /// 条件判断函数
+ /// 条件为假时返回原值,否则返回null
+ public static TSource? TakeUnless(
+ this TSource value,
+ Func predicate)
+ where TSource : class
+ => !predicate(value) ? value : null;
+
+ ///
+ /// Repeat:重复执行函数n次
+ ///
+ /// 输入值的类型
+ /// 初始输入值
+ /// 重复执行的次数
+ /// 要重复执行的函数
+ /// 经过多次变换后的最终值
+ public static TSource Repeat(
+ this TSource value,
+ int times,
+ Func func)
+ {
+ var result = value;
+ for (int i = 0; i < times; i++)
+ {
+ result = func(result);
+ }
+ return result;
+ }
+
+ ///
+ /// Try:安全执行,捕获异常
+ ///
+ /// 输入值的类型
+ /// 函数返回结果的类型
+ /// 要传递给函数的输入值
+ /// 要安全执行的函数
+ /// 包含执行状态、结果和错误信息的元组
+ public static (bool success, TResult? result, Exception? error) Try(
+ this TSource value,
+ Func func)
+ {
+ try
+ {
+ return (true, func(value), null);
+ }
+ catch (Exception ex)
+ {
+ return (false, default, ex);
+ }
+ }
+
+ ///
+ /// Memoize:缓存函数结果
+ ///
+ /// 函数输入参数的类型
+ /// 函数返回结果的类型
+ /// 要缓存结果的函数
+ /// 带有缓存功能的包装函数
+ public static Func Memoize(
+ this Func func)
+ where TSource : notnull
+ {
+ var cache = new Dictionary();
+ return x =>
+ {
+ if (cache.TryGetValue(x, out var result))
+ return result;
+ result = func(x);
+ cache[x] = result;
+ return result;
+ };
+ }
+}