C#中嵌套Record实例属性的非破坏性修改简洁语法问询
嵌套Record深层属性的非破坏性修改方案
嘿,我正好碰到过类似的问题!你原来的写法失效是因为C#的with表达式只能直接操作当前层级的属性,没法直接通过.访问嵌套属性来赋值——这是语法规则限制。不过我们有两种简洁的方式实现你的需求,既保留非破坏性修改的特性,又不用手动指定所有未改动的属性:
1. 原生语法:逐层嵌套使用with表达式
这是最直接的原生解决方案,虽然看起来有几层嵌套,但完全符合C# Record的设计逻辑,而且能确保只修改目标属性,其他所有属性都会原样保留:
// 先初始化一个示例数据 var data = new RepoMetadata(new JsonPaths( new RadarrMetadata(new[] { "old-custom-format" }), new SonarrMetadata(new[] { "existing-release-profile" }) )); // 逐层修改深层的CustomFormats属性 var modifiedData = data with { JsonPaths = data.JsonPaths with { Radarr = data.JsonPaths.Radarr with { CustomFormats = new[] { "newvalue" } } } };
这样修改后,modifiedData.JsonPaths.Sonarr会完全保留原来的ReleaseProfiles值,只有Radarr.CustomFormats被更新,完美符合你的需求。
2. 进阶方案:封装扩展方法简化调用
如果觉得嵌套的with不够清爽,可以给每个Record类型写对应的扩展方法,把深层修改的逻辑封装起来,后续调用就会非常简洁:
// 给RadarrMetadata扩展修改CustomFormats的方法 public static RadarrMetadata WithCustomFormats(this RadarrMetadata metadata, IReadOnlyCollection<string> newFormats) { return metadata with { CustomFormats = newFormats }; } // 给JsonPaths扩展修改Radarr.CustomFormats的方法 public static JsonPaths WithRadarrCustomFormats(this JsonPaths paths, IReadOnlyCollection<string> newFormats) { return paths with { Radarr = paths.Radarr.WithCustomFormats(newFormats) }; } // 给RepoMetadata扩展直接修改最底层CustomFormats的方法 public static RepoMetadata WithRadarrCustomFormats(this RepoMetadata repo, IReadOnlyCollection<string> newFormats) { return repo with { JsonPaths = repo.JsonPaths.WithRadarrCustomFormats(newFormats) }; }
现在修改属性只需要一行代码就能搞定:
var modifiedData = data.WithRadarrCustomFormats(new[] { "newvalue" });
这种方式把嵌套修改的细节完全隐藏起来,调用方只需要关心要修改的目标属性,而且同样是非破坏性修改,不会影响原对象的任何其他属性。
补充:为什么原写法不生效?
再解释下你原来的写法失败的原因:C#的with表达式的初始化器只允许直接指定当前类型的属性,不能通过JsonPaths.Radarr.CustomFormats这种嵌套路径来赋值,编译器无法识别这种语法,所以会报错。
内容的提问来源于stack exchange,提问作者void.pointer
相关产品推荐
相关产品推荐

