mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-22 19:03:29 +08:00
- 将 GFramework.Core.Functional 命名空间统一改为 GFramework.Core.functional - 更新 AsyncFunctionalExtensions.cs 中的命名空间声明 - 移除不必要的 using 指令,包括 GFramework.Core.Functional 的导入 - 调整测试文件中的命名空间引用以匹配新的命名空间格式 - 确保所有相关文件都使用一致的小写命名空间约定
421 lines
14 KiB
C#
421 lines
14 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.
|
||
|
||
using System.Diagnostics.Contracts;
|
||
|
||
namespace GFramework.Core.functional;
|
||
|
||
/// <summary>
|
||
/// 表示一个操作的结果,可能是成功值或异常
|
||
/// </summary>
|
||
public readonly struct Result<A> : IEquatable<Result<A>>, IComparable<Result<A>>
|
||
{
|
||
private readonly A? _value;
|
||
private readonly Exception? _exception;
|
||
|
||
// ------------------------------------------------------------------ 状态枚举
|
||
|
||
/// <summary>
|
||
/// 表示 Result 结构体的内部状态
|
||
/// </summary>
|
||
private enum ResultState : byte
|
||
{
|
||
/// <summary>
|
||
/// 未初始化状态,表示 Result 尚未被赋值
|
||
/// </summary>
|
||
Bottom,
|
||
|
||
/// <summary>
|
||
/// 失败状态,表示操作执行失败并包含异常信息
|
||
/// </summary>
|
||
Faulted,
|
||
|
||
/// <summary>
|
||
/// 成功状态,表示操作执行成功并包含返回值
|
||
/// </summary>
|
||
Success
|
||
}
|
||
|
||
private readonly ResultState _state;
|
||
|
||
// ------------------------------------------------------------------ 静态默认值
|
||
|
||
/// <summary>
|
||
/// 表示未初始化的 Bottom 状态
|
||
/// </summary>
|
||
public static readonly Result<A> Bottom = default;
|
||
|
||
// ------------------------------------------------------------------ 构造器
|
||
|
||
/// <summary>
|
||
/// 构造成功结果
|
||
/// </summary>
|
||
/// <param name="value">成功的值</param>
|
||
public Result(A value)
|
||
{
|
||
_state = ResultState.Success;
|
||
_value = value;
|
||
_exception = null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 构造失败结果
|
||
/// </summary>
|
||
/// <param name="exception">失败的异常</param>
|
||
public Result(Exception exception)
|
||
{
|
||
_state = ResultState.Faulted;
|
||
_exception = exception ?? throw new ArgumentNullException(nameof(exception));
|
||
_value = default;
|
||
}
|
||
|
||
// ------------------------------------------------------------------ 隐式转换
|
||
|
||
/// <summary>
|
||
/// 隐式将值转换为成功结果
|
||
/// </summary>
|
||
/// <param name="value">要转换的值</param>
|
||
/// <returns>成功结果</returns>
|
||
[Pure]
|
||
public static implicit operator Result<A>(A value) => new(value);
|
||
|
||
// ------------------------------------------------------------------ 状态属性
|
||
|
||
/// <summary>
|
||
/// 判断结果是否为成功状态
|
||
/// </summary>
|
||
[Pure]
|
||
public bool IsSuccess => _state == ResultState.Success;
|
||
|
||
/// <summary>
|
||
/// 判断结果是否为失败状态
|
||
/// </summary>
|
||
[Pure]
|
||
public bool IsFaulted => _state == ResultState.Faulted;
|
||
|
||
|
||
/// <summary>
|
||
/// 判断结果是否为未初始化的 Bottom 状态
|
||
/// </summary>
|
||
[Pure]
|
||
public bool IsBottom => _state == ResultState.Bottom;
|
||
|
||
/// <summary>
|
||
/// 获取内部异常:
|
||
/// - 若为 Failure 状态,则返回内部异常
|
||
/// - 若为 Bottom 状态,则返回带有 "Result is in Bottom state." 消息的 InvalidOperationException
|
||
/// - 若为 Success 状态,则返回带有 "Cannot access Exception on a successful Result." 消息的 InvalidOperationException
|
||
/// </summary>
|
||
[Pure]
|
||
public Exception Exception => _exception
|
||
?? (IsBottom
|
||
? new InvalidOperationException("Result is in Bottom state.")
|
||
: new InvalidOperationException(
|
||
"Cannot access Exception on a successful Result."));
|
||
|
||
// ------------------------------------------------------------------ 取值
|
||
|
||
/// <summary>
|
||
/// 若成功则返回值,若失败则返回默认值
|
||
/// </summary>
|
||
/// <param name="defaultValue">失败时返回的默认值</param>
|
||
/// <returns>成功时的值或默认值</returns>
|
||
[Pure]
|
||
public A IfFail(A defaultValue) => IsSuccess ? _value! : defaultValue;
|
||
|
||
/// <summary>
|
||
/// 若成功则返回值,若失败则通过委托处理异常
|
||
/// </summary>
|
||
/// <param name="f">处理异常的委托</param>
|
||
/// <returns>成功时的值或委托处理后的结果</returns>
|
||
[Pure]
|
||
public A IfFail(Func<Exception, A> f) => IsSuccess ? _value! : f(Exception);
|
||
|
||
/// <summary>
|
||
/// 若失败则执行副作用
|
||
/// </summary>
|
||
/// <param name="f">处理异常的副作用委托</param>
|
||
public void IfFail(Action<Exception> f)
|
||
{
|
||
if (IsFaulted) f(Exception);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 若成功则执行副作用
|
||
/// </summary>
|
||
/// <param name="f">处理成功值的副作用委托</param>
|
||
public void IfSucc(Action<A> f)
|
||
{
|
||
if (IsSuccess) f(_value!);
|
||
}
|
||
|
||
// ------------------------------------------------------------------ 变换
|
||
|
||
/// <summary>
|
||
/// 成功时映射值,失败时透传异常
|
||
/// </summary>
|
||
/// <typeparam name="B">映射后的类型</typeparam>
|
||
/// <param name="f">映射函数</param>
|
||
/// <returns>映射后的结果</returns>
|
||
[Pure]
|
||
public Result<B> Map<B>(Func<A, B> f)
|
||
{
|
||
ArgumentNullException.ThrowIfNull(f);
|
||
return IsSuccess ? new Result<B>(f(_value!)) : new Result<B>(Exception);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 成功时绑定到新 Result,失败时透传异常
|
||
/// </summary>
|
||
/// <typeparam name="B">绑定后的类型</typeparam>
|
||
/// <param name="binder">绑定函数</param>
|
||
/// <returns>绑定后的结果</returns>
|
||
[Pure]
|
||
public Result<B> Bind<B>(Func<A, Result<B>> binder)
|
||
{
|
||
ArgumentNullException.ThrowIfNull(binder);
|
||
return IsSuccess ? binder(_value!) : new Result<B>(Exception);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 异步映射
|
||
/// </summary>
|
||
/// <typeparam name="B">映射后的类型</typeparam>
|
||
/// <param name="f">异步映射函数</param>
|
||
/// <returns>异步映射后的结果</returns>
|
||
[Pure]
|
||
public async Task<Result<B>> MapAsync<B>(Func<A, Task<B>> f)
|
||
{
|
||
ArgumentNullException.ThrowIfNull(f);
|
||
if (!IsSuccess) return new Result<B>(Exception);
|
||
|
||
try
|
||
{
|
||
return new Result<B>(await f(_value!));
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
return new Result<B>(ex);
|
||
}
|
||
}
|
||
|
||
// ------------------------------------------------------------------ 模式匹配
|
||
|
||
/// <summary>
|
||
/// 对成功/失败两种情况分别处理并返回值
|
||
/// </summary>
|
||
/// <typeparam name="R">返回值类型</typeparam>
|
||
/// <param name="succ">处理成功值的函数</param>
|
||
/// <param name="fail">处理异常的函数</param>
|
||
/// <returns>处理后的结果</returns>
|
||
[Pure]
|
||
public R Match<R>(Func<A, R> succ, Func<Exception, R> fail) =>
|
||
IsSuccess ? succ(_value!) : fail(Exception);
|
||
|
||
/// <summary>
|
||
/// 对成功/失败两种情况分别执行副作用
|
||
/// </summary>
|
||
/// <param name="succ">处理成功值的副作用委托</param>
|
||
/// <param name="fail">处理异常的副作用委托</param>
|
||
public void Match(Action<A> succ, Action<Exception> fail)
|
||
{
|
||
if (IsSuccess) succ(_value!);
|
||
else fail(Exception);
|
||
}
|
||
|
||
// ------------------------------------------------------------------ 静态工厂(语义更清晰)
|
||
|
||
/// <summary>
|
||
/// 创建成功结果
|
||
/// </summary>
|
||
/// <param name="value">成功的值</param>
|
||
/// <returns>成功结果</returns>
|
||
[Pure]
|
||
public static Result<A> Succeed(A value) => new(value);
|
||
|
||
/// <summary>
|
||
/// 创建成功结果(别名)
|
||
/// </summary>
|
||
/// <param name="value">成功的值</param>
|
||
/// <returns>成功结果</returns>
|
||
[Pure]
|
||
public static Result<A> Success(A value) => new(value);
|
||
|
||
/// <summary>
|
||
/// 创建失败结果
|
||
/// </summary>
|
||
/// <param name="ex">失败的异常</param>
|
||
/// <returns>失败结果</returns>
|
||
[Pure]
|
||
public static Result<A> Fail(Exception ex) => new(ex);
|
||
|
||
/// <summary>
|
||
/// 创建失败结果(别名)
|
||
/// </summary>
|
||
/// <param name="ex">失败的异常</param>
|
||
/// <returns>失败结果</returns>
|
||
[Pure]
|
||
public static Result<A> Failure(Exception ex) => new(ex);
|
||
|
||
/// <summary>
|
||
/// 根据错误消息创建失败结果
|
||
/// </summary>
|
||
/// <param name="message">错误消息</param>
|
||
/// <returns>失败结果</returns>
|
||
[Pure]
|
||
public static Result<A> Failure(string message) => new(new Exception(message));
|
||
|
||
/// <summary>
|
||
/// 安全执行委托,自动捕获异常
|
||
/// </summary>
|
||
/// <param name="f">要执行的委托</param>
|
||
/// <returns>执行结果</returns>
|
||
public static Result<A> Try(Func<A> f)
|
||
{
|
||
ArgumentNullException.ThrowIfNull(f);
|
||
try
|
||
{
|
||
return new Result<A>(f());
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
return new Result<A>(ex);
|
||
}
|
||
}
|
||
|
||
// ------------------------------------------------------------------ 相等 / 比较
|
||
|
||
/// <summary>
|
||
/// 判断两个结果是否相等
|
||
/// </summary>
|
||
/// <param name="other">另一个结果</param>
|
||
/// <returns>若相等返回 true,否则返回 false</returns>
|
||
[Pure]
|
||
public bool Equals(Result<A> other)
|
||
{
|
||
if (_state != other._state) return false;
|
||
if (IsSuccess) return EqualityComparer<A>.Default.Equals(_value, other._value);
|
||
if (IsFaulted)
|
||
return Exception.GetType() == other.Exception.GetType()
|
||
&& Exception.Message == other.Exception.Message;
|
||
return true; // both Bottom
|
||
}
|
||
|
||
/// <summary>
|
||
/// 判断对象是否与当前结果相等
|
||
/// </summary>
|
||
/// <param name="obj">要比较的对象</param>
|
||
/// <returns>若相等返回 true,否则返回 false</returns>
|
||
[Pure]
|
||
public override bool Equals(object? obj) => obj is Result<A> other && Equals(other);
|
||
|
||
/// <summary>
|
||
/// 获取结果的哈希码
|
||
/// </summary>
|
||
/// <returns>哈希码</returns>
|
||
[Pure]
|
||
public override int GetHashCode() => IsSuccess
|
||
? HashCode.Combine(0, _value)
|
||
: HashCode.Combine(1, Exception.GetType(), Exception.Message);
|
||
|
||
/// <summary>
|
||
/// 比较两个结果的大小
|
||
/// </summary>
|
||
/// <param name="other">另一个结果</param>
|
||
/// <returns>比较结果</returns>
|
||
[Pure]
|
||
public int CompareTo(Result<A> other)
|
||
{
|
||
// Bottom < Faulted < Success
|
||
if (_state != other._state) return _state.CompareTo(other._state);
|
||
if (!IsSuccess) return 0;
|
||
|
||
try
|
||
{
|
||
return Comparer<A>.Default.Compare(_value, other._value);
|
||
}
|
||
catch (ArgumentException)
|
||
{
|
||
// 类型不可比较时返回 0
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 判断两个结果是否相等
|
||
/// </summary>
|
||
/// <param name="a">第一个结果</param>
|
||
/// <param name="b">第二个结果</param>
|
||
/// <returns>若相等返回 true,否则返回 false</returns>
|
||
[Pure]
|
||
public static bool operator ==(Result<A> a, Result<A> b) => a.Equals(b);
|
||
|
||
/// <summary>
|
||
/// 判断两个结果是否不相等
|
||
/// </summary>
|
||
/// <param name="a">第一个结果</param>
|
||
/// <param name="b">第二个结果</param>
|
||
/// <returns>若不相等返回 true,否则返回 false</returns>
|
||
[Pure]
|
||
public static bool operator !=(Result<A> a, Result<A> b) => !a.Equals(b);
|
||
|
||
/// <summary>
|
||
/// 判断第一个结果是否小于第二个结果
|
||
/// </summary>
|
||
/// <param name="a">第一个结果</param>
|
||
/// <param name="b">第二个结果</param>
|
||
/// <returns>若小于返回 true,否则返回 false</returns>
|
||
[Pure]
|
||
public static bool operator <(Result<A> a, Result<A> b) => a.CompareTo(b) < 0;
|
||
|
||
/// <summary>
|
||
/// 判断第一个结果是否小于等于第二个结果
|
||
/// </summary>
|
||
/// <param name="a">第一个结果</param>
|
||
/// <param name="b">第二个结果</param>
|
||
/// <returns>若小于等于返回 true,否则返回 false</returns>
|
||
[Pure]
|
||
public static bool operator <=(Result<A> a, Result<A> b) => a.CompareTo(b) <= 0;
|
||
|
||
/// <summary>
|
||
/// 判断第一个结果是否大于第二个结果
|
||
/// </summary>
|
||
/// <param name="a">第一个结果</param>
|
||
/// <param name="b">第二个结果</param>
|
||
/// <returns>若大于返回 true,否则返回 false</returns>
|
||
[Pure]
|
||
public static bool operator >(Result<A> a, Result<A> b) => a.CompareTo(b) > 0;
|
||
|
||
/// <summary>
|
||
/// 判断第一个结果是否大于等于第二个结果
|
||
/// </summary>
|
||
/// <param name="a">第一个结果</param>
|
||
/// <param name="b">第二个结果</param>
|
||
/// <returns>若大于等于返回 true,否则返回 false</returns>
|
||
[Pure]
|
||
public static bool operator >=(Result<A> a, Result<A> b) => a.CompareTo(b) >= 0;
|
||
|
||
// ------------------------------------------------------------------ 调试
|
||
|
||
/// <summary>
|
||
/// 返回结果的字符串表示
|
||
/// </summary>
|
||
/// <returns>结果的字符串表示</returns>
|
||
[Pure]
|
||
public override string ToString() => _state switch
|
||
{
|
||
ResultState.Success => _value?.ToString() ?? "(null)",
|
||
ResultState.Faulted => $"Fail({Exception.Message})",
|
||
_ => "(Bottom)"
|
||
};
|
||
} |