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

C#使用with表达式复制record类型时如何追加列表属性值

实现方法

Tags = original.Tags + "C"无法编译的核心原因是List<T>类型未重载+运算符:C#仅为字符串、委托等少数内置类型预定义了该运算,无法直接通过+实现列表元素追加。同时with表达式对引用类型成员默认执行浅拷贝,若要保证副本的Tags属性与原对象完全独立、且无需手动枚举全部原有元素即可追加新值,可使用以下几种实现方案:

方案1:直接初始化新列表时传入原集合(最贴合原示例逻辑)

不需要手动列出所有原有标签,直接将原Tags作为新List的构造入参,再通过集合初始化器追加新元素即可。新生成的List是独立实例,后续修改原对象的Tags不会影响副本,和原示例行为完全一致:

var original = new TaggedNumber(1, new List<string> { "A", "B" });
// 无需手动写"A","B"即可追加"C"
var copy = original with { 
    Tags = new List<string>(original.Tags) { "C" } 
};

执行后copy.PrintTags()会直接输出A, B, C,后续执行original.Tags.Add("C")也不会改动copy的Tags值。

方案2:封装扩展方法简化调用

如果需要频繁做这类列表追加生成副本的操作,可以封装一个通用扩展方法,减少重复代码:

public static class CollectionExtensions
{
    /// <summary>
    /// 基于现有列表创建新列表并追加指定元素
    /// </summary>
    public static List<T> AppendNew<T>(this List<T> source, T item)
    {
        var newList = new List<T>(source);
        newList.Add(item);
        return newList;
    }
}

后续使用with表达式时可以直接简化为:

var copy = original with { Tags = original.Tags.AppendNew("C") };

方案3:使用不可变集合(最适配with不可变修改语义)

with表达式本身是为不可变数据修改设计的,如果你的场景允许修改record的Tags类型,换用ImmutableList<T>会更顺手:

  1. 首先引入对应命名空间:using System.Collections.Immutable;
  2. 修改record定义:
    public record TaggedNumber(int Number, ImmutableList<string> Tags)
    {
        public string PrintTags() => string.Join(", ", Tags);
    }
    
  3. 初始化和创建副本的写法会非常简洁,且天然不存在引用共享问题:
    var original = new TaggedNumber(1, ImmutableList.Create("A", "B"));
    // ImmutableList的Add方法会返回追加元素后的新集合实例
    var copy = original with { Tags = original.Tags.Add("C") };
    

❗ 避坑提醒:不要写成var copy = original with { Tags = { "C" } };,这种嵌套初始化器的写法不会创建新List,而是直接在原对象引用的List实例上调用Add,会直接修改original的Tags值,打破副本和原对象的隔离,不符合原示例的预期行为。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 03:18:16