C#中泛型类型参数未知且未使用时如何进行模式匹配?
解决方案
你可以选择以下几种无装箱、低侵入的实现方案,按推荐优先级排序:
方案1:基类新增抽象属性(最简洁)
如果可以修改Error基类的定义,直接在基类加抽象的错误消息属性,所有子类统一实现:
internal abstract record Error { public abstract string ErrorMessage { get; } } // 你的泛型record只需补充重写逻辑 private sealed record ErrorStrWithEnum<TEnum>(string Error, TEnum Enum) : Error where TEnum : struct, Enum { public override string ErrorMessage => Error; }
后续使用时不需要任何模式匹配,直接访问属性即可:
var message = error.ErrorMessage;
该方案完全无额外开销,代码逻辑最直观。
方案2:新增非泛型接口(零侵入基类)
如果不能修改Error基类,给泛型record实现一个非泛型的消息接口即可:
// 定义非泛型接口 internal interface IHasErrorMessage { string Error { get; } } // 让泛型record实现接口 private sealed record ErrorStrWithEnum<TEnum>(string Error, TEnum Enum) : Error, IHasErrorMessage where TEnum : struct, Enum
匹配时直接判断接口类型:
var message = error switch { IHasErrorMessage err => err.Error, // 其他Error子类的匹配分支 _ => string.Empty };
该方案同样无装箱、无运行时额外开销,不需要修改现有基类逻辑。
方案3:反射匹配(仅适用无法修改类定义的场景)
如果完全不能修改现有任何类的定义,可以用反射提取属性,仅适合非高频调用场景:
var message = error switch { var e when e.GetType().IsGenericType && e.GetType().GetGenericTypeDefinition() == typeof(ErrorStrWithEnum<>) => (string)e.GetType().GetProperty(nameof(Error)).GetValue(e), _ => string.Empty };
该方案有反射开销,不建议在性能敏感路径使用。
内容的提问来源于stack exchange,提问作者Pavel Voronin
相关产品推荐
相关产品推荐

