C# Result模式:合并数组型Result的泛型转换问题求助
解决Result协变问题实现合并多个数组Result对象
问题核心:Result<T>是泛型类,默认不支持协变。虽然string[]实现了IEnumerable<string>,但Result<string[]>无法隐式转换为Result<IEnumerable<string>>,导致调用Flatten时出错。
下面是几种可行的解决方案:
方案一:改用协变接口(最优雅)
泛型类不能声明协变,但接口可以。把Result<T>包装成支持协变的接口,就能实现类型隐式转换:
class Result { public static IResult<T> Create<T>(T value) => new ResultImpl<T>(value); public static IResult<IEnumerable<T>> Flatten<T>(params IResult<IEnumerable<T>>[] results) { return new ResultImpl<IEnumerable<T>>(results.SelectMany(x => x.Value)); } } // 声明协变接口,out关键字表示T是输出类型(只读) interface IResult<out T> { T Value { get; } } // 原Result<T>改名为ResultImpl,实现协变接口 class ResultImpl<T> : IResult<T> { internal ResultImpl(T value) => Value = value; public T Value { get; internal set; } } // 调用完全正常 var result1 = Result.Create<string[]>(["A", "B"]); var result2 = Result.Create<string[]>(["C", "D"]); var result3 = Result.Create<string[]>(["E", "F"]); var result = Result.Flatten<string>(result1, result2, result3);
原理:协变接口IResult<out T>允许将派生类型的接口实例转换为基类型的接口实例,这里string[]是IEnumerable<string>的派生类型,所以IResult<string[]>可以转IResult<IEnumerable<string>>。
方案二:重载Flatten方法
如果不想改动现有Result的结构,直接给Flatten加一个数组重载:
class Result { public static Result<T> Create<T>(T value) => new Result<T>(value); // 处理IEnumerable<T>的原方法 public static Result<IEnumerable<T>> Flatten<T>(params Result<IEnumerable<T>>[] results) { return new Result<IEnumerable<T>>(results.SelectMany(x => x.Value)); } // 新增处理T[]的重载 public static Result<IEnumerable<T>> Flatten<T>(params Result<T[]>[] results) { return new Result<IEnumerable<T>>(results.SelectMany(x => x.Value)); } } // 直接调用即可,编译器会匹配到数组重载 var result = Result.Flatten<string>(result1, result2, result3);
方案三:显式转换(临时应急)
调用时手动把每个Result<string[]>转成Result<IEnumerable<string>>,这种方式比较繁琐,适合临时场景:
var result = Result.Flatten<string>( Result.Create<IEnumerable<string>>(result1.Value), Result.Create<IEnumerable<string>>(result2.Value), Result.Create<IEnumerable<string>>(result3.Value) );
内容的提问来源于stack exchange,提问作者Kyle
相关产品推荐
相关产品推荐

