You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义Either类型适配LINQ查询的SelectMany方法签名应如何定义?

多泛型参数类型的SelectMany签名确定方法

C# 的 LINQ 查询语法采用鸭子类型匹配,不要求类型实现特定接口,只要方法签名符合查询表达式的转换规则即可。你可以直接把 IEnumerable<> 的标准 SelectMany 签名作为模板,按你的自定义类型的结构做替换即可。

泛型参数映射规则

针对 Either<L, R> 这类右偏的双泛型类型(LINQ 操作仅作用于右侧的成功值,左侧为固定的错误通道,出现 Left 直接短路),和标准 IEnumerable 签名的对应关系如下:

标准IEnumerable签名的泛型参数对应Either的参数含义
TSource源Either包裹的右侧成功值类型
TCollectioncollectionSelector返回的Either包裹的右侧成功值类型
TResult最终返回的Either包裹的右侧结果值类型
无对应固定的左侧错误类型L,全程不变

正确的Either SelectMany签名

对应替换后的标准签名如下:

public static Either<L, TResult> SelectMany<TSource, TCollection, TResult, L>(
    this Either<L, TSource> source,
    Func<TSource, Either<L, TCollection>> collectionSelector,
    Func<TSource, TCollection, TResult> resultSelector
)
{
    // 短路逻辑:任意一步为Left直接返回
    if (source.IsLeft) return new Left<L, TResult>(source.Left);
    var midEither = collectionSelector(source.Right);
    if (midEither.IsLeft) return new Left<L, TResult>(midEither.Left);
    // 两个都为Right时,传入两个成功值调用结果转换函数
    return new Right<L, TResult>(resultSelector(source.Right, midEither.Right));
}

现有实现的问题

你当前能运行的实现其实是简化的特化版本:

  • 你把collectionSelector返回的Either的右侧值类型固定为和源Either一致的R,限制了跨类型的from查询
  • 你给resultSelector传入了inner.Left,实际上Left场景已经提前短路,永远不会走到这一步的逻辑,属于无效代码

所有多泛型类型的通用套用方法

不管你的自定义类型有多少个泛型参数,都可以按以下步骤确定SelectMany签名:

  1. 确定类型的「偏置参数」:即LINQ操作实际作用的那个泛型参数,比如Task的偏置参数是返回值T,Transition的偏置参数是结果值,剩下的泛型参数都是全程固定的通道参数
  2. 把标准SelectMany签名里所有的IEnumerable<T>占位符,替换为你的自定义类型,把通道参数固定,把偏置参数位置留出来对应TSource/TCollection/TResult
  3. 保持参数顺序和标准签名完全一致,不需要做额外调整

规范参考

相关规则可以直接查阅C#语言规范的「查询表达式」章节,里面明确规定了多from子句的转换逻辑,该规则对所有类型通用,没有专门针对多泛型参数的特殊文档,因为规则本身就是开放式的。

内容的提问来源于stack exchange,提问作者Tim Barrass

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 02:51:01