C#中含枚举的构造函数互相调用时的参数验证问题
问题分析与解决方法
为什么原写法编译报错?
你尝试的写法foo?.MyEnum ?? throw new ArgumentNullException(nameof(foo))存在两个核心问题:
- 可空类型不匹配:
foo?.MyEnum的返回类型是TEnum?(可空枚举)——因为foo是引用类型,当foo为null时,?.运算符会返回值类型的可空版本。但目标构造函数接受的是非可空的TEnum,枚举作为值类型无法直接将TEnum?隐式转换为TEnum。 - 运算符类型兼容问题:
??运算符要求左右两侧类型必须兼容,左边是TEnum?,右边是ArgumentNullException(类型为Exception),两者类型不匹配,因此编译报错。
可行的验证方式
要解决CA1062警告同时避免编译错误,需要先验证foo本身不为null,再访问其MyEnum属性,推荐以下简洁写法:
public class Foo<TEnum> where TEnum : Enum { public Foo(TEnum myEnum) { MyEnum = myEnum; } public Foo(Foo<TEnum> foo) : this((foo ?? throw new ArgumentNullException(nameof(foo))).MyEnum) { } public TEnum MyEnum { get; } }
原理说明
foo ?? throw new ArgumentNullException(nameof(foo))会优先判断foo是否为null:如果是,直接抛出异常;如果不是,返回foo本身。- 由于已经确保
foo非null,后续访问foo.MyEnum得到的是确定的非空TEnum值,完全符合目标构造函数的参数要求,同时满足CA1062对参数非空验证的要求。
另一种可选写法(避免构造函数初始化器)
如果不想依赖构造函数初始化器,也可以在拷贝构造函数内手动验证并赋值,但会重复赋值逻辑:
public Foo(Foo<TEnum> foo) { if (foo == null) throw new ArgumentNullException(nameof(foo)); MyEnum = foo.MyEnum; }
这种写法同样能解决CA1062警告,但不如第一种写法简洁,因为重复了MyEnum的赋值逻辑。
内容的提问来源于stack exchange,提问作者lonix
相关产品推荐
相关产品推荐

