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

如何避免IReadOnlyCollection<T>含默认项?有无禁止默认值的不可变集合?

问题解答

核心疑问

是否存在禁止用默认值初始化的不可变集合,以此避免因集合中包含default(MyObject)(引用类型即null),导致后续调用Clone方法时程序崩溃的问题?

场景复现

当前代码中,用默认值初始化数组的写法:

var newObjects = new MyObject[]
{
    default
};

MyObject的Clone方法在对象为默认值(null)时会抛出异常,因为直接访问了未初始化的属性:

public MyObject Clone()
{
    return new MyObject(ShortName, Name);
}

调用CopyObjects遍历集合时,会因null对象调用Clone触发崩溃:

public IEnumerable<MyObject> CopyObjects(IReadOnlyCollection<MyObject> newObjects)
{
    var newLst = new List<MyObject>(); 
    foreach (var o in newObjects)
    {
        newLst.Add(o.Clone());
    }

    return newLst;
}

解决方案分析

1. 原生集合无此限制

.NET原生的不可变集合(如ImmutableList<T>、ImmutableArray<T>)本身不会阻止添加default(T),需要从数据校验逻辑层面解决问题,而非依赖集合本身的特性。

2. 可行解决思路

  • 自定义带校验的不可变集合:封装原生不可变集合,在添加元素时校验是否为默认值,违规则抛出异常。示例:
public sealed class NonDefaultImmutableList<T>
{
    private readonly ImmutableList<T> _innerList;

    private NonDefaultImmutableList(ImmutableList<T> innerList)
    {
        _innerList = innerList;
    }

    public static NonDefaultImmutableList<T> Empty => new NonDefaultImmutableList<T>(ImmutableList<T>.Empty);

    public NonDefaultImmutableList<T> Add(T item)
    {
        if (EqualityComparer<T>.Default.Equals(item, default(T)))
        {
            throw new ArgumentException("禁止添加默认值到集合中", nameof(item));
        }
        return new NonDefaultImmutableList<T>(_innerList.Add(item));
    }

    // 按需实现AddRange、Remove等其他不可变集合方法,均添加校验逻辑
    public IEnumerator<T> GetEnumerator() => _innerList.GetEnumerator();
}

使用时,添加default(MyObject)会直接触发报错,从源头避免后续崩溃。

  • 在业务方法中添加校验:在CopyObjects遍历克隆前,先过滤或校验null对象:
public IEnumerable<MyObject> CopyObjects(IReadOnlyCollection<MyObject> newObjects)
{
    var newLst = new List<MyObject>(); 
    foreach (var o in newObjects)
    {
        if (o == null)
        {
            // 可选:抛出异常、跳过或记录日志
            throw new InvalidOperationException("Null对象无法执行克隆操作");
            // 或者跳过该元素:continue;
        }
        newLst.Add(o.Clone());
    }

    return newLst;
}
  • 优化实体类的容错性:在Clone方法内部处理默认值情况:
public MyObject Clone()
{
    if (this == null)
    {
        // 可返回null或一个空实例,根据业务需求选择
        return null;
        // return new MyObject(string.Empty, string.Empty);
    }
    return new MyObject(ShortName, Name);
}

总结

.NET没有原生的不可变集合会自动禁止默认值初始化,但可以通过自定义带校验的不可变集合、在业务方法中加入校验逻辑或优化实体类方法的容错性,从源头或中间环节避免因默认值导致的程序崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 20:10:11