You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中含枚举的构造函数互相调用时的参数验证问题

问题分析与解决方法

为什么原写法编译报错?

你尝试的写法foo?.MyEnum ?? throw new ArgumentNullException(nameof(foo))存在两个核心问题:

  1. 可空类型不匹配:foo?.MyEnum的返回类型是TEnum?(可空枚举)——因为foo是引用类型,当foo为null时,?.运算符会返回值类型的可空版本。但目标构造函数接受的是非可空的TEnum,枚举作为值类型无法直接将TEnum?隐式转换为TEnum。
  2. 运算符类型兼容问题:??运算符要求左右两侧类型必须兼容,左边是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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 11:08:28