C#中如何让编译器识别Result<T>已排除失败类型,直接获取成功值?
优雅处理Result的编译期类型推断问题
针对你遇到的场景,这里提供几种简洁且类型安全的实现方式,无需额外冗余判断或强制转换:
1. 扩展方法封装(推荐)
将类型判断和取值逻辑封装到扩展方法中,调用方只需一行代码完成取值或异常抛出:
public static class ResultExtensions { public static T GetValueOrThrow<T>(this Result<T> result) { return result switch { ResultSuccess<T> success => success.Value, ResultFailure<T> failure => throw new Exception($"操作失败:{failure.ErrorMessage}"), _ => throw new UnreachableException("未知的Result子类,违反类型约束") }; } }
调用示例:
var result = DoSomething(); var value = result.GetValueOrThrow(); // 直接获取值,失败时自动抛出异常
2. 利用switch表达式的穷尽性检查
如果你的Result<T>基类是抽象类,且仅存在ResultSuccess<T>和ResultFailure<T>两个子类(确保无其他子类可继承,比如将基类构造函数设为internal),C#编译器会识别模式匹配的穷尽性,无需处理"其他"情况:
var result = DoSomething(); var value = result switch { ResultFailure<T> failure => throw new Exception($"操作失败:{failure.ErrorMessage}"), ResultSuccess<T> success => success.Value };
若编译器仍要求默认分支,可添加_ => throw new UnreachableException(),该分支永远不会执行,但能消除编译警告。
3. 优化类结构为封闭继承(C# 9+)
使用C# 9的record类型或密封类嵌套,让编译器明确知道Result<T>的所有可能子类,进一步强化类型推断:
方式A:抽象Record继承
public abstract record Result<T>; public record ResultSuccess<T>(T Value) : Result<T>; public record ResultFailure<T>(string ErrorMessage) : Result<T>;
方式B:密封基类+嵌套子类
public abstract class Result<T> { // 私有构造函数,确保仅嵌套子类可继承 private Result() { } public sealed class ResultSuccess : Result<T> { public T Value { get; } public ResultSuccess(T value) => Value = value; } public sealed class ResultFailure : Result<T> { public string ErrorMessage { get; } public ResultFailure(string errorMessage) => ErrorMessage = errorMessage; } }
此时使用switch表达式或模式匹配时,编译器会自动识别穷尽性,无需额外处理分支。
内容的提问来源于stack exchange,提问作者Darren Oakey
相关产品推荐
相关产品推荐

