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

C#编译器bug问询:Nullable<decimal>为何可赋值给仅支持decimal转换的类

问题结论

这不是C#编译器的bug,是符合C#语言规范的合法行为,你遇到的是可空用户自定义转换的自动提升规则的作用。

规则说明

C#规范明确定义了用户自定义转换的提升逻辑:当存在从非可空值类型S到类型T的隐式用户自定义转换时,编译器会自动生成对应的提升转换,支持从S?(可空值类型)到T的隐式转换,转换规则如下:

  • 若源S?实例为null,直接返回T类型的默认值(引用类型默认值为null,值类型为对应默认值),不会触发你定义的转换逻辑
  • 若源S?实例有值,先取出内部的S类型值,执行你定义的用户自定义转换得到T类型实例,作为转换结果返回
对应你的代码场景

你定义了从decimal(非可空值类型S)到DecimalWrapper(引用类型T)的隐式转换,编译器会自动生成从decimal?到DecimalWrapper的隐式提升转换。你传入(decimal?)null时,匹配到这个提升转换,直接返回DecimalWrapper的默认值null,因此编译合法,运行结果也符合规则预期。

你可以通过传入带值的decimal?验证规则:DecimalWrapper c = (decimal?)1.23m;同样可以正常编译,运行时会触发你定义的转换逻辑得到DecimalWrapper实例。

禁用该行为的方案

如果你不允许null的隐式转换,可以通过显式定义decimal?的转换操作符覆盖编译器的自动提升逻辑,示例如下:

public class DecimalWrapper
{
    public static implicit operator DecimalWrapper(decimal x) => new();
    // 显式定义decimal?的转换,覆盖自动提升逻辑
    public static implicit operator DecimalWrapper(decimal? x)
    {
        // 此处可以按你的需求加逻辑,比如禁止null转换直接抛异常
        if (!x.HasValue)
            throw new System.ArgumentNullException(nameof(x), "不允许null转换为DecimalWrapper");
        return new DecimalWrapper();
    }
}

如果需要直接禁止decimal?的隐式转换,可以将上述操作符改为explicit,或者在启用C# 8+可空引用类型的前提下,将DecimalWrapper标记为非可空类型,编译器会对null赋值的行为抛出警告,你可以将对应警告等级调整为错误即可阻止编译。


内容的提问来源于stack exchange,提问作者videokojot

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 06:24:01