如何让C#中的with表达式支持类类型?
类类型实现类似
with表达式的替代方案 C#原生的with表达式仅支持记录类型(record)和结构体(struct),普通类无法直接使用,会触发CS8858编译错误。针对大量数据对象、不愿逐个添加复制构造函数的场景,可通过以下方式实现类似“复制对象并修改指定成员”的功能:
1. 通用扩展方法封装克隆+修改逻辑
写一个通用扩展方法,结合序列化或反射实现克隆,再链式执行修改操作,语法接近with:
using System.Text.Json; public static class ObjectExtensions { // 基于Json序列化的浅克隆实现,可按需替换为深克隆逻辑 public static T With<T>(this T source, Action<T> modify) where T : class { if (source == null) throw new ArgumentNullException(nameof(source)); var clone = JsonSerializer.Deserialize<T>(JsonSerializer.Serialize(source)); modify(clone); return clone; } } // 使用示例 var copy = someInstance.With(x => { x.SomeProperty = "newValue"; x.AnotherProperty = 123; });
注意:这种方式是浅克隆,如果对象包含引用类型成员,需要调整为深克隆(比如修改Json序列化配置,或改用反射遍历成员复制)。
2. 结合映射器简化代码
如果已经在使用AutoMapper等映射工具,可以通过映射器的配置实现更简洁的写法:
// 方式1:使用AfterMap回调 var copy = Mapper.Map<SomeClass>(someInstance, opt => opt.AfterMap((_, dest) => dest.SomeProperty = "newValue") ); // 方式2:结合匿名类型(若映射器支持从匿名类型映射) var copy = Mapper.Map<SomeClass>(new { someInstance.Property, SomeProperty = "newValue" });
3. 为类添加自定义的With系列方法
如果是自己维护的类,可以针对性编写类型安全的WithXXX方法,性能比序列化更好:
public class SomeClass { public string Property { get; set; } public string SomeProperty { get; set; } public int AnotherProperty { get; set; } // 复制当前实例并修改指定属性 public SomeClass WithSomeProperty(string value) { return new SomeClass { Property = this.Property, AnotherProperty = this.AnotherProperty, SomeProperty = value }; } // 支持链式调用多个修改 public SomeClass WithAnotherProperty(int value) { return new SomeClass { Property = this.Property, SomeProperty = this.SomeProperty, AnotherProperty = value }; } } // 使用示例 var copy = someInstance.WithSomeProperty("newValue").WithAnotherProperty(456);
这种方式类型安全、性能最优,但需要为每个常用的修改场景编写对应方法,适合高频修改的类。
4. 源生成器自动生成克隆代码
可以借助C#源生成器,在编译时自动为类生成类似记录的with功能代码。比如自定义一个SupportsWithAttribute,然后编写源生成器扫描标记了该属性的类,自动生成包含克隆+修改逻辑的扩展方法,实现和原生with几乎一致的语法体验。
内容的提问来源于stack exchange,提问作者Jeff Mercado
相关产品推荐
相关产品推荐

