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

C#类构造函数接收集合参数:如何避免不必要的列表拷贝?

类存储集合参数的选型与避免不必要拷贝的方案

一、集合参数类型的选择

当类需要存储传入的集合参数时,优先根据场景选择以下类型:

  • IReadOnlyList<T>/IReadOnlyCollection<T>:作为参数类型时,明确告知调用方该集合仅用于读取,无需修改,自身存储时也能保证对外暴露的不可变性。
  • IEnumerable<T>:如果需要兼容更广泛的集合来源(比如LINQ查询结果、自定义迭代器等),可以用它作为参数,但内部需要做额外处理来避免性能损耗和确保不可变性。

二、避免IEnumerable<T>处理时的多余拷贝

如果用IEnumerable<T>作为参数,直接调用items.ToList().AsReadOnly()会在很多场景下产生不必要的拷贝(比如传入的已经是List<T>或者只读集合)。可以通过类型判断+构造函数重载的方式优化:

优化后的事件参数类示例

public class CustomEventArgs : EventArgs
{
    public IReadOnlyList<ItemType> Items { get; }

    // 兼容最广泛的IEnumerable<T>输入
    public CustomEventArgs(IEnumerable<ItemType> items)
    {
        Items = items switch
        {
            IReadOnlyList<ItemType> readOnly => readOnly,
            List<ItemType> list => list.AsReadOnly(),
            _ => items.ToList().AsReadOnly()
        };
    }

    // 直接接受List<T>,跳过类型检查,直接包装为只读
    public CustomEventArgs(List<ItemType> items)
    {
        Items = items.AsReadOnly();
    }

    // 直接接受只读集合,直接复用
    public CustomEventArgs(IReadOnlyList<ItemType> items)
    {
        Items = items;
    }
}

优化逻辑说明

  • 当调用new CustomEventArgs(new List<ItemType> { item1, item2 })时,会匹配List<T>重载,直接调用AsReadOnly()生成只读包装,无集合拷贝。
  • 当传入内部维护的_items(比如List<T>类型),同样通过重载直接包装,避免拷贝。
  • 仅当传入的是只能单次枚举的IEnumerable<T>(比如LINQ查询结果、自定义迭代器)时,才会执行ToList()拷贝为列表,再转只读。

额外注意事项

如果需要存储的是集合的快照(即原集合后续修改不影响存储的内容),那么无论传入什么类型,都必须执行拷贝。但如果事件发布者能保证原集合在发布后不会被修改,用AsReadOnly()包装即可,既保证不可变性又避免性能损耗。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 17:15:05