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

静态对象构造顺序疑问:调用WebColor.FromCode为何触发空引用异常?

问题:静态对象构造时机导致的NullReferenceException

我原本认为类的静态对象会在类首次被引用时构造,但遇到了不符合预期的行为。现有如下抽象泛型类、子类及调用代码,运行时会抛出NullReferenceException,请分析原因。

抽象泛型类代码

public abstract class SmartColor<TColor> where TColor : SmartColor<TColor> {
    private static readonly ConcurrentDictionary<string, TColor> _items = new();

    protected SmartColor(string code, string name) {
        Code = code;
        Name = name;
        //register all colors
        foreach (var field in typeof(TColor).GetFields(BindingFlags.Public | BindingFlags.Static)) {
            TColor? item = (TColor?)field.GetValue(null);
            if (item is not null) {
                Register(item);
            }
        }
    }

    public string Code { get; }

    public string Name { get; }

    public static TColor FromCode(string code) {
        if (_items.TryGetValue(code, out var result)) {
            return result;
        }
        return null;
    }

    private void Register(TColor item) {
        _items.GetOrAdd(item.Code, item);
    }
}

子类代码

public class WebColor : SmartColor<WebColor> {
    public static readonly WebColor White = new WebColor("#ffffff", nameof(White));
    public static readonly WebColor Black = new WebColor("#000000", nameof(Black));

    protected WebColor(string code, string name) : base(code, name) {
    }
}

调用代码

public static void Main()
{
    WebColor color = WebColor.FromCode("#ffffff");
    Console.WriteLine(color.Name);
}

异常原因分析

核心触发原因:静态初始化时机不匹配

调用WebColor.FromCode("#ffffff")时,本质是调用基类泛型封闭类型SmartColor<WebColor>的静态方法,CLR只会初始化SmartColor<WebColor>的静态成员(即_items字典),不会触发子类WebColor的静态字段(White、Black)的初始化。此时_items字典为空,FromCode返回null,后续访问color.Name自然抛出NullReferenceException。

额外逻辑缺陷(即使触发子类初始化仍存在问题)

假设通过访问WebColor.White等方式触发了子类静态初始化,原代码的基类构造函数逻辑仍有漏洞:

  • 静态字段按代码顺序初始化,当构造第一个实例(White)时,基类构造函数反射遍历子类静态字段,此时White字段尚未完成赋值(对象构造完成后才会给字段赋值),Black字段也未开始初始化,两者都为null,因此没有任何实例被注册到_items。
  • 当构造第二个实例(Black)时,基类构造函数反射遍历字段,此时White已完成初始化会被注册,但Black字段仍处于构造中、值为null,无法被注册,最终_items中只有White,缺少Black。

验证示例

若在FromCode前先触发子类静态初始化,异常即可避免:

public static void Main()
{
    // 访问子类静态字段,触发WebColor的静态初始化
    var _ = WebColor.White;
    WebColor color = WebColor.FromCode("#ffffff");
    Console.WriteLine(color.Name); // 输出White
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 09:09:54