feat(functional): 添加Result类型及其扩展方法支持

- 引入Result<TSuccess, TError>结构体用于表示可能成功或失败的计算结果
- 实现Result类型的Success和Failure静态工厂方法
- 添加SuccessValue和ErrorValue属性用于获取对应值
- 创建ResultExtensions扩展类提供Map、Bind、MapError和Match方法
- 在FunctionExtensions中添加TryResult方法将异常安全执行封装为Result类型
- 更新Try方法的文档注释以反映新的功能和返回类型
This commit is contained in:
GeWuYou 2026-01-31 21:31:33 +08:00
parent fd3a9ae9e0
commit c9dd969b05
3 changed files with 158 additions and 8 deletions

View File

@ -11,6 +11,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
using GFramework.Core.functional.types;
namespace GFramework.Core.functional.functions;
/// <summary>
@ -79,28 +81,31 @@ public static class FunctionExtensions
return result;
}
/// <summary>
/// Try安全执行捕获异常
/// 尝试执行一个转换函数并将结果包装在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>(
/// <typeparam name="TResult">转换函数返回值的类型</typeparam>
/// <param name="value">要进行转换操作的源值</param>
/// <param name="func">用于转换源值的函数委托</param>
/// <returns>如果转换成功则返回包含结果的成功状态,如果发生异常则返回包含异常信息的失败状态</returns>
public static Result<TResult, Exception> TryResult<TSource, TResult>(
this TSource value,
Func<TSource, TResult> func)
{
// 执行转换函数并处理可能的异常
try
{
return (true, func(value), null);
return Result<TResult, Exception>.Success(func(value));
}
catch (Exception ex)
{
return (false, default, ex);
return Result<TResult, Exception>.Failure(ex);
}
}
/// <summary>
/// Memoize缓存函数结果
/// </summary>

View File

@ -0,0 +1,91 @@
// 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

@ -0,0 +1,54 @@
// 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);
}
}