// 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
{
///
/// TakeIf:条件返回值或null
///
/// 输入值的类型
/// 要进行条件判断的输入值
/// 条件判断函数
/// 条件为真时返回原值,否则返回null
public static TSource? TakeIf(
this TSource value,
Func predicate)
where TSource : class
{
return predicate(value) ? value : null;
}
///
/// TakeUnless:条件相反的TakeIf
///
/// 输入值的类型
/// 要进行条件判断的输入值
/// 条件判断函数
/// 条件为假时返回原值,否则返回null
public static TSource? TakeUnless(
this TSource value,
Func predicate)
where TSource : class
{
return !predicate(value) ? value : null;
}
///
/// TakeIfValue:值类型版本的 TakeIf,返回 Nullable
///
/// 值类型
/// 要进行条件判断的输入值
/// 条件判断函数
/// 条件为真时返回原值,否则返回 null
/// 当 predicate 为 null 时抛出
///
///
/// var result = 42.TakeIfValue(x => x > 0); // 42
/// var result2 = -5.TakeIfValue(x => x > 0); // null
///
///
public static TSource? TakeIfValue(
this TSource value,
Func predicate)
where TSource : struct
{
ArgumentNullException.ThrowIfNull(predicate);
return predicate(value) ? value : null;
}
///
/// TakeUnlessValue:值类型版本的 TakeUnless,返回 Nullable
///
/// 值类型
/// 要进行条件判断的输入值
/// 条件判断函数
/// 条件为假时返回原值,否则返回 null
/// 当 predicate 为 null 时抛出
///
/// x < 0); // 42
/// var result2 = -5.TakeUnlessValue(x => x < 0); // null
/// ]]>
///
public static TSource? TakeUnlessValue(
this TSource value,
Func predicate)
where TSource : struct
{
ArgumentNullException.ThrowIfNull(predicate);
return !predicate(value) ? value : null;
}
///
/// When:条件执行,满足条件时执行操作并返回原值
///
/// 值的类型
/// 输入值
/// 条件判断函数
/// 满足条件时执行的操作
/// 原始值
/// 当 predicate 或 action 为 null 时抛出
///
///
/// var result = 42
/// .When(x => x > 0, x => Console.WriteLine($"Positive: {x}"))
/// .When(x => x % 2 == 0, x => Console.WriteLine("Even"));
///
///
public static TSource When(
this TSource value,
Func predicate,
Action action)
{
ArgumentNullException.ThrowIfNull(predicate);
ArgumentNullException.ThrowIfNull(action);
if (predicate(value))
action(value);
return value;
}
///
/// RepeatUntil:重复执行函数直到条件满足
///
/// 值的类型
/// 初始值
/// 每次迭代执行的函数
/// 停止条件
/// 最大迭代次数(防止无限循环)
/// 满足条件时的值
/// 当 func 或 predicate 为 null 时抛出
/// 当 maxIterations 小于 1 时抛出
/// 当达到最大迭代次数仍未满足条件时抛出
///
///
/// var result = 1.RepeatUntil(
/// x => x * 2,
/// x => x >= 100,
/// maxIterations: 10
/// ); // 128
///
///
public static TSource RepeatUntil(
this TSource value,
Func func,
Func 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;
}
///
/// Retry:同步重试机制,失败时重试指定次数
///
/// 返回值类型
/// 要执行的函数
/// 最大重试次数
/// 每次重试之间的延迟(毫秒)
/// 函数执行结果
/// 当 func 为 null 时抛出
/// 当 maxRetries 小于 0 或 delayMilliseconds 小于 0 时抛出
/// 当所有重试都失败时抛出,包含所有异常
///
///
/// var result = ControlExtensions.Retry(
/// () => UnstableOperation(),
/// maxRetries: 3,
/// delayMilliseconds: 100
/// );
///
///
public static TResult Retry(
Func func,
int maxRetries = 3,
int delayMilliseconds = 0)
{
ArgumentNullException.ThrowIfNull(func);
ArgumentOutOfRangeException.ThrowIfNegative(maxRetries);
ArgumentOutOfRangeException.ThrowIfNegative(delayMilliseconds);
var exceptions = new List();
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);
}
}