From 5318f5a38f6d2547b9085c3413979b4163bb6c20 Mon Sep 17 00:00:00 2001 From: GeWuYou <95328647+GeWuYou@users.noreply.github.com> Date: Sat, 31 Jan 2026 14:45:16 +0800 Subject: [PATCH] =?UTF-8?q?refactor(functional):=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E5=BC=8F=E7=BC=96=E7=A8=8B=E6=89=A9=E5=B1=95?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E7=BB=84=E7=BB=87=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将原有的 PipeExtensions.cs 文件拆分为多个专门的功能模块 - 新增 ControlExtensions.cs 专门处理控制流扩展方法 - 新增 EnumerableExtensions.cs 专门处理集合相关扩展方法 - 新增 FunctionExtensions.cs 专门处理函数式编程核心功能 - 新增 TypeExtensions.cs 专门处理类型转换相关扩展方法 - 移除 PipeExtensions.cs 中的集合操作、函数式核心功能和控制流方法 - 保留 PipeExtensions.cs 中的管道操作相关核心方法 - 优化代码组织结构提升可维护性和可读性 --- .../collections/EnumerableExtensions.cs | 59 ++++ .../functional/control/ControlExtensions.cs | 118 ++++++++ .../functions/FunctionExtensions.cs | 125 ++++++++ .../functional/pipe/PipeExtensions.cs | 266 +----------------- .../functional/types/TypeExtensions.cs | 44 +++ 5 files changed, 348 insertions(+), 264 deletions(-) create mode 100644 GFramework.Core/functional/collections/EnumerableExtensions.cs create mode 100644 GFramework.Core/functional/control/ControlExtensions.cs create mode 100644 GFramework.Core/functional/functions/FunctionExtensions.cs create mode 100644 GFramework.Core/functional/types/TypeExtensions.cs diff --git a/GFramework.Core/functional/collections/EnumerableExtensions.cs b/GFramework.Core/functional/collections/EnumerableExtensions.cs new file mode 100644 index 0000000..1fb2e09 --- /dev/null +++ b/GFramework.Core/functional/collections/EnumerableExtensions.cs @@ -0,0 +1,59 @@ +// Copyright (c) 2025 GeWuYou +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +namespace GFramework.Core.functional.collections; + +/// +/// 提供集合的函数式编程扩展方法 +/// +public static class EnumerableExtensions +{ + /// + /// Map:对集合中的每个元素应用函数 + /// + /// 源集合元素的类型 + /// 映射后集合元素的类型 + /// 要映射的源集合 + /// 用于转换元素的函数 + /// 映射后的元素序列 + public static IEnumerable Map( + this IEnumerable source, + Func selector) + => source.Select(selector); + + /// + /// Filter:过滤集合 + /// + /// 集合元素的类型 + /// 要过滤的源集合 + /// 用于确定是否包含元素的条件函数 + /// 满足条件的元素序列 + public static IEnumerable Filter( + this IEnumerable source, + Func predicate) + => source.Where(predicate); + + /// + /// Reduce:将集合归约为单个值 + /// + /// 集合元素的类型 + /// 归约结果的类型 + /// 要归约的源集合 + /// 初始累加值 + /// 累加器函数 + /// 归约后的最终值 + public static TResult Reduce( + this IEnumerable source, + TResult seed, + Func accumulator) + => source.Aggregate(seed, accumulator); +} diff --git a/GFramework.Core/functional/control/ControlExtensions.cs b/GFramework.Core/functional/control/ControlExtensions.cs new file mode 100644 index 0000000..2e0ab2d --- /dev/null +++ b/GFramework.Core/functional/control/ControlExtensions.cs @@ -0,0 +1,118 @@ +// 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.control; + +/// +/// 控制流扩展方法类,提供函数式编程风格的控制结构 +/// +public static class ControlExtensions +{ + /// + /// 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); + + /// + /// 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; +} diff --git a/GFramework.Core/functional/functions/FunctionExtensions.cs b/GFramework.Core/functional/functions/FunctionExtensions.cs new file mode 100644 index 0000000..b2c04e1 --- /dev/null +++ b/GFramework.Core/functional/functions/FunctionExtensions.cs @@ -0,0 +1,125 @@ +// 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.functions; + +/// +/// 函数式编程扩展方法集合,提供柯里化、偏函数应用、重复执行、安全执行和缓存等功能 +/// +public static class FunctionExtensions +{ + /// + /// 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); + + /// + /// 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; + }; + } +} diff --git a/GFramework.Core/functional/pipe/PipeExtensions.cs b/GFramework.Core/functional/pipe/PipeExtensions.cs index 3ce37ad..595789e 100644 --- a/GFramework.Core/functional/pipe/PipeExtensions.cs +++ b/GFramework.Core/functional/pipe/PipeExtensions.cs @@ -73,46 +73,6 @@ public static class PipeExtensions 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:将函数应用于值(柯里化辅助) /// @@ -125,140 +85,7 @@ public static class PipeExtensions 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:执行操作并返回原值 /// @@ -287,94 +114,5 @@ public static class PipeExtensions 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; - }; - } + } diff --git a/GFramework.Core/functional/types/TypeExtensions.cs b/GFramework.Core/functional/types/TypeExtensions.cs new file mode 100644 index 0000000..937998f --- /dev/null +++ b/GFramework.Core/functional/types/TypeExtensions.cs @@ -0,0 +1,44 @@ +// Copyright (c) 2025 GeWuYou +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +namespace GFramework.Core.functional.types; + +/// +/// 提供类型转换相关的扩展方法 +/// +public static class TypeExtensions +{ + /// + /// 安全类型转换方法,将源类型转换为目标类型 + /// 如果转换失败或值为null,则返回null而不抛出异常 + /// + /// 源类型参数 + /// 目标类型参数,必须为引用类型 + /// 需要进行类型转换的源值 + /// 转换成功时返回目标类型实例,失败时返回null + public static TResult? As( + this TSource value) + where TResult : class + => value as TResult; + + /// + /// 强制类型转换方法,将对象转换为指定的目标类型 + /// 转换失败时会抛出InvalidCastException异常 + /// + /// 目标类型参数 + /// 需要进行强制类型转换的对象 + /// 转换后的目标类型实例 + /// 当转换失败时抛出此异常 + public static TResult Cast( + this object value) + => (TResult)value; +}