为何IReadOnlyCollection无法触发Either类型的隐式转换?
问题分析:隐式转换结构体Either的编译异常问题
问题场景
定义了带隐式转换的只读结构体Either<TLeft, TRight>,以及接收Either<IReadOnlyCollection<int>, int>的记录类型SomeType。测试时,直接传入IReadOnlyCollection<int>类型的变量编译失败,但传入int[]类型的变量却能正常编译——明明前者和Either的Left类型完全匹配,请问原因是什么?
复现代码
public readonly struct Either<TLeft, TRight> { public TLeft? Left { get; } = default; public TRight? Right { get; } = default; public static implicit operator Either<TLeft, TRight>(TLeft left) => new(left); public static implicit operator Either<TLeft, TRight>(TRight right) => new(right); private Either(TLeft left) => Left = left; private Either(TRight right) => Right = right; } public record SomeType(Either<IReadOnlyCollection<int>, int> Something); public class Class1 { public void Run() { IReadOnlyCollection<int> test1 = new[] { 1, 2 }; int[] test2 = new[] { 1, 2 }; var d1 = new SomeType(test1); // 编译失败 var d2 = new SomeType(test2); // 编译正常 } }
编译错误信息
参数类型“System.Collections.Generic.IReadOnlyCollection
”无法分配给参数类型“EitherExperiments.Either<System.Collections.Generic.IReadOnlyCollection , int>”
原因解析
这是C#隐式转换解析规则导致的:
- 对于
test2(int[]类型),编译器可完成链式隐式转换:先将int[]转换为IReadOnlyCollection<int>(数组实现了该接口,属于引用转换),再调用Either<IReadOnlyCollection<int>, int>的左值隐式转换操作符,最终得到目标类型,整个路径唯一且明确。 - 对于
test1(IReadOnlyCollection<int>类型),问题出在泛型隐式转换的类型推断限制:Either<TLeft, TRight>的隐式转换是泛型静态方法,编译器需要先确定TLeft和TRight的具体类型才能匹配操作符。当传入IReadOnlyCollection<int>时,编译器无法唯一确定目标Either的类型参数——它没办法排除该值会不会被匹配到右侧的TRight=int转换(尽管逻辑上不可能,但编译器不会做语义层面的判断),因此无法找到符合要求的隐式转换路径。
解决方法
要让test1的调用正常编译,可显式指定转换类型,帮编译器明确目标类型:
var d1 = new SomeType((Either<IReadOnlyCollection<int>, int>)test1);
内容的提问来源于stack exchange,提问作者mnj
相关产品推荐
相关产品推荐

