namespace MS.Microservice.Core.Functional { /// /// 表示"无值"的单例类型,用于构造 的 None 状态。 /// /// /// /// 直接使用 工厂属性即可得到此类型的唯一实例, /// 再配合 的隐式转换运算符即可将其转换为任意泛型的 None。 /// /// /// 来源:《C# 函数式编程》第 3.2 节 — 使用 Option 表示可选数据。 /// /// public readonly struct NoneType { /// 返回字符串 "None" public override string ToString() => "None"; } /// /// 包含非 null 值的 Option 容器,表示 Option 的"有值"状态。 /// /// 被包装的值类型。 /// /// /// 不要直接构造 ,应使用 工厂方法。 /// 不允许包含 null;若需要表示缺失值,请使用 。 /// /// /// 来源:《C# 函数式编程》第 3.2 节 — 使用 Option 表示可选数据。 /// /// public readonly struct Some { /// 被包装的非 null 值。 internal T Value { get; } internal Some(T value) { // Some 不允许包含 null;缺失值应通过 None 表示 ArgumentNullException.ThrowIfNull(value, nameof(value)); Value = value; } /// public override string ToString() => $"Some({Value})"; public static implicit operator Some(T value) => new(value); } /// /// 表示可能存在、也可能不存在的值。 /// 用于函数式编程中替代 null 引用和裸 null 检查,消除 。 /// /// 可选值的类型。 /// /// /// 有两种状态: /// /// Some(value):包含一个非 null 的值。 /// None:表示值不存在。 /// /// /// /// 推荐使用 工厂类创建实例: /// /// Option<int> some = F.Some(42); /// Option<int> none = F.None; /// /// 或利用隐式转换: /// /// Option<string> opt = "hello"; // Some("hello") /// Option<string> opt2 = null; // None /// /// /// /// 使用 进行模式匹配: /// /// string result = opt.Match( /// none: () => "no value", /// some: v => $"value is {v}"); /// /// /// /// 来源:《C# 函数式编程》第 3.2 ~ 3.4 节 — Option、Map、Bind。 /// /// public readonly struct Option : IEquatable> { private readonly T? _value; private readonly bool _isSome; private Option(T value) { _isSome = true; _value = value; } /// /// 表示"无值"的静态 None 实例,等同于 default(Option<T>)。 /// public static readonly Option None = default; /// /// 指示当前 Option 是否包含值(Some 状态)。 /// public bool IsSome => _isSome; /// /// 指示当前 Option 是否不含值(None 状态)。 /// public bool IsNone => !_isSome; // ── 隐式转换 ──────────────────────────────────────────────────────────── /// /// 从 隐式转换为 None 状态的 。 /// 允许直接将 赋值给 Option 变量。 /// public static implicit operator Option(NoneType _) => default; /// /// 从 隐式转换为 Some 状态的 。 /// public static implicit operator Option(Some some) => new(some.Value); /// /// 从值 隐式转换为 。 /// null 值自动变为 None,非 null 值自动变为 Some。 /// public static implicit operator Option(T? value) => value is null ? None : new Option(value); // ── 核心操作 ───────────────────────────────────────────────────────────── /// /// 对 Option 进行模式匹配: /// 若为 None 则执行 ,若为 Some 则执行 。 /// /// 返回结果的类型。 /// None 分支的处理函数(无参数)。 /// Some 分支的处理函数(接收内部值)。 /// 由所选分支产生的结果。 /// /// Match 是 Option 上最基础的操作;所有其他操作(Map、Bind、GetOrElse 等) /// 都可以通过 Match 实现,保证了穷举(exhaustive)的模式处理。 /// public R Match(Func none, Func some) => _isSome ? some(_value!) : none(); /// /// Match 重载:允许 分支直接写 () => F.None, /// 分支返回 ,与书中 Applicative 示例写法保持一致。 /// /// some 分支返回的 Option 内部值类型。 /// /// None 分支,惯用写法为 () => F.None; /// 该 lambda 的返回值被忽略,实际直接短路为 Option<R>.None。 /// /// /// Some 分支,接收内部值并返回 。 /// Some<R> 可通过隐式转换自动提升为 。 /// /// /// /// 为什么需要此重载:C# 泛型类型推断不使用隐式转换,因此当两个分支 /// 分别返回 时, /// 编译器无法为 Match<R>(Func<R>, Func<T, R>) 推断出统一的 R。 /// 此重载将 none 签名显式声明为 Func<NoneType>, /// 编译器据此选择本重载并从 some 分支推断 R,再通过隐式转换将 NoneType 提升为 Option<R>。 /// /// /// 来源:《C# 函数式编程》第 5.3 节 — Applicative 风格 Option 组合。 /// /// public Option Match(Func none, Func> some) => _isSome ? some(_value!) : none(); /// /// Match 重载:允许 分支直接返回 /// (即 t => F.Some(expr) 写法),配合 none: () => F.None 消除类型推断歧义。 /// /// Some 分支包装的值类型。 /// /// 与 Match<R>(Func<NoneType>, Func<T, Option<R>>) 互补: /// 当 some lambda 直接返回 F.Some(...)(推断类型为 )时, /// 编译器无法将 Some<R> 映射到 Option<R>,需要此重载显式指定返回类型。 /// 通过隐式转换自动提升为 。 /// public Option Match(Func none, Func> some) => _isSome ? some(_value!) : none(); // ── 相等性 ──────────────────────────────────────────────────────────────── /// public bool Equals(Option other) { if (IsNone && other.IsNone) return true; if (IsSome && other.IsSome) return EqualityComparer.Default.Equals(_value, other._value); return false; } /// public override bool Equals(object? obj) => obj is Option other && Equals(other); /// public override int GetHashCode() => _isSome ? _value!.GetHashCode() : 0; /// /// Some 状态返回 "Some(value)",None 状态返回 "None"。 /// public override string ToString() => _isSome ? $"Some({_value})" : "None"; /// 两个 Option 相等当且仅当状态相同且(若都为 Some)内部值相等。 public static bool operator ==(Option left, Option right) => left.Equals(right); /// 两个 Option 不相等。 public static bool operator !=(Option left, Option right) => !left.Equals(right); } }