mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-22 18:52:08 +08:00
- 添加ControlExtensions的TakeIfValue、TakeUnlessValue、When、RepeatUntil和Retry方法测试 - 添加FunctionExtensions的Compose、AndThen、Curry、Uncurry、Defer和Once方法测试 - 添加Option<T>类型的完整测试套件,包括工厂方法、取值、变换、过滤、模式匹配等功能 - 添加PipeExtensions的Tap、Pipe、Let、PipeIf方法测试 - 移除AsyncExtensionsTests中的WhenAll相关测试 - 移除NumericExtensionsTests中的Clamp测试 - 更新ObjectExtensionsTests中Do方法为Also方法的测试 - 修复ControlExtensions文档中的XML代码标签格式 - 在AsyncExtensionsTests中添加对GFramework.Core.Functional.Async的引用 - 在ObjectExtensionsTests中添加对GFramework.Core.functional.pipe的引用
225 lines
8.2 KiB
C#
225 lines
8.2 KiB
C#
// 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;
|
||
|
||
/// <summary>
|
||
/// 控制流扩展方法类,提供函数式编程风格的控制结构
|
||
/// </summary>
|
||
public static class ControlExtensions
|
||
{
|
||
/// <summary>
|
||
/// TakeIf:条件返回值或null
|
||
/// </summary>
|
||
/// <typeparam name="TSource">输入值的类型</typeparam>
|
||
/// <param name="value">要进行条件判断的输入值</param>
|
||
/// <param name="predicate">条件判断函数</param>
|
||
/// <returns>条件为真时返回原值,否则返回null</returns>
|
||
public static TSource? TakeIf<TSource>(
|
||
this TSource value,
|
||
Func<TSource, bool> predicate)
|
||
where TSource : class
|
||
{
|
||
return predicate(value) ? value : null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// TakeUnless:条件相反的TakeIf
|
||
/// </summary>
|
||
/// <typeparam name="TSource">输入值的类型</typeparam>
|
||
/// <param name="value">要进行条件判断的输入值</param>
|
||
/// <param name="predicate">条件判断函数</param>
|
||
/// <returns>条件为假时返回原值,否则返回null</returns>
|
||
public static TSource? TakeUnless<TSource>(
|
||
this TSource value,
|
||
Func<TSource, bool> predicate)
|
||
where TSource : class
|
||
{
|
||
return !predicate(value) ? value : null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// TakeIfValue:值类型版本的 TakeIf,返回 Nullable
|
||
/// </summary>
|
||
/// <typeparam name="TSource">值类型</typeparam>
|
||
/// <param name="value">要进行条件判断的输入值</param>
|
||
/// <param name="predicate">条件判断函数</param>
|
||
/// <returns>条件为真时返回原值,否则返回 null</returns>
|
||
/// <exception cref="ArgumentNullException">当 predicate 为 null 时抛出</exception>
|
||
/// <example>
|
||
/// <code><![CDATA[
|
||
/// var result = 42.TakeIfValue(x => x > 0); // 42
|
||
/// var result2 = -5.TakeIfValue(x => x > 0); // null
|
||
/// ]]></code>
|
||
/// </example>
|
||
public static TSource? TakeIfValue<TSource>(
|
||
this TSource value,
|
||
Func<TSource, bool> predicate)
|
||
where TSource : struct
|
||
{
|
||
ArgumentNullException.ThrowIfNull(predicate);
|
||
return predicate(value) ? value : null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// TakeUnlessValue:值类型版本的 TakeUnless,返回 Nullable
|
||
/// </summary>
|
||
/// <typeparam name="TSource">值类型</typeparam>
|
||
/// <param name="value">要进行条件判断的输入值</param>
|
||
/// <param name="predicate">条件判断函数</param>
|
||
/// <returns>条件为假时返回原值,否则返回 null</returns>
|
||
/// <exception cref="ArgumentNullException">当 predicate 为 null 时抛出</exception>
|
||
/// <example>
|
||
/// <code><![CDATA[
|
||
/// var result = 42.TakeUnlessValue(x => x < 0); // 42
|
||
/// var result2 = -5.TakeUnlessValue(x => x < 0); // null
|
||
/// ]]></code>
|
||
/// </example>
|
||
public static TSource? TakeUnlessValue<TSource>(
|
||
this TSource value,
|
||
Func<TSource, bool> predicate)
|
||
where TSource : struct
|
||
{
|
||
ArgumentNullException.ThrowIfNull(predicate);
|
||
return !predicate(value) ? value : null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// When:条件执行,满足条件时执行操作并返回原值
|
||
/// </summary>
|
||
/// <typeparam name="TSource">值的类型</typeparam>
|
||
/// <param name="value">输入值</param>
|
||
/// <param name="predicate">条件判断函数</param>
|
||
/// <param name="action">满足条件时执行的操作</param>
|
||
/// <returns>原始值</returns>
|
||
/// <exception cref="ArgumentNullException">当 predicate 或 action 为 null 时抛出</exception>
|
||
/// <example>
|
||
/// <code>
|
||
/// var result = 42
|
||
/// .When(x => x > 0, x => Console.WriteLine($"Positive: {x}"))
|
||
/// .When(x => x % 2 == 0, x => Console.WriteLine("Even"));
|
||
/// </code>
|
||
/// </example>
|
||
public static TSource When<TSource>(
|
||
this TSource value,
|
||
Func<TSource, bool> predicate,
|
||
Action<TSource> action)
|
||
{
|
||
ArgumentNullException.ThrowIfNull(predicate);
|
||
ArgumentNullException.ThrowIfNull(action);
|
||
|
||
if (predicate(value))
|
||
action(value);
|
||
|
||
return value;
|
||
}
|
||
|
||
/// <summary>
|
||
/// RepeatUntil:重复执行函数直到条件满足
|
||
/// </summary>
|
||
/// <typeparam name="TSource">值的类型</typeparam>
|
||
/// <param name="value">初始值</param>
|
||
/// <param name="func">每次迭代执行的函数</param>
|
||
/// <param name="predicate">停止条件</param>
|
||
/// <param name="maxIterations">最大迭代次数(防止无限循环)</param>
|
||
/// <returns>满足条件时的值</returns>
|
||
/// <exception cref="ArgumentNullException">当 func 或 predicate 为 null 时抛出</exception>
|
||
/// <exception cref="ArgumentOutOfRangeException">当 maxIterations 小于 1 时抛出</exception>
|
||
/// <exception cref="InvalidOperationException">当达到最大迭代次数仍未满足条件时抛出</exception>
|
||
/// <example>
|
||
/// <code>
|
||
/// var result = 1.RepeatUntil(
|
||
/// x => x * 2,
|
||
/// x => x >= 100,
|
||
/// maxIterations: 10
|
||
/// ); // 128
|
||
/// </code>
|
||
/// </example>
|
||
public static TSource RepeatUntil<TSource>(
|
||
this TSource value,
|
||
Func<TSource, TSource> func,
|
||
Func<TSource, bool> predicate,
|
||
int maxIterations = 1000)
|
||
{
|
||
ArgumentNullException.ThrowIfNull(func);
|
||
ArgumentNullException.ThrowIfNull(predicate);
|
||
ArgumentOutOfRangeException.ThrowIfLessThan(maxIterations, 1);
|
||
|
||
var current = value;
|
||
var iterations = 0;
|
||
|
||
while (!predicate(current))
|
||
{
|
||
if (iterations >= maxIterations)
|
||
throw new InvalidOperationException(
|
||
$"RepeatUntil 达到最大迭代次数 {maxIterations} 但条件仍未满足");
|
||
|
||
current = func(current);
|
||
iterations++;
|
||
}
|
||
|
||
return current;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Retry:同步重试机制,失败时重试指定次数
|
||
/// </summary>
|
||
/// <typeparam name="TResult">返回值类型</typeparam>
|
||
/// <param name="func">要执行的函数</param>
|
||
/// <param name="maxRetries">最大重试次数</param>
|
||
/// <param name="delayMilliseconds">每次重试之间的延迟(毫秒)</param>
|
||
/// <returns>函数执行结果</returns>
|
||
/// <exception cref="ArgumentNullException">当 func 为 null 时抛出</exception>
|
||
/// <exception cref="ArgumentOutOfRangeException">当 maxRetries 小于 0 或 delayMilliseconds 小于 0 时抛出</exception>
|
||
/// <exception cref="AggregateException">当所有重试都失败时抛出,包含所有异常</exception>
|
||
/// <example>
|
||
/// <code>
|
||
/// var result = ControlExtensions.Retry(
|
||
/// () => UnstableOperation(),
|
||
/// maxRetries: 3,
|
||
/// delayMilliseconds: 100
|
||
/// );
|
||
/// </code>
|
||
/// </example>
|
||
public static TResult Retry<TResult>(
|
||
Func<TResult> func,
|
||
int maxRetries = 3,
|
||
int delayMilliseconds = 0)
|
||
{
|
||
ArgumentNullException.ThrowIfNull(func);
|
||
ArgumentOutOfRangeException.ThrowIfNegative(maxRetries);
|
||
ArgumentOutOfRangeException.ThrowIfNegative(delayMilliseconds);
|
||
|
||
var exceptions = new List<Exception>();
|
||
var attempts = maxRetries + 1;
|
||
|
||
for (var i = 0; i < attempts; i++)
|
||
{
|
||
try
|
||
{
|
||
return func();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
exceptions.Add(ex);
|
||
|
||
if (i < maxRetries && delayMilliseconds > 0)
|
||
Thread.Sleep(delayMilliseconds);
|
||
}
|
||
}
|
||
|
||
throw new AggregateException(
|
||
$"操作在 {attempts} 次尝试后仍然失败",
|
||
exceptions);
|
||
}
|
||
} |