C#中实现类似JS扩展运算符的对象属性复制方案咨询
在C#中实现类似JS扩展运算符的对象属性复制方案
嘿,这个需求太有共鸣了!JS里的...扩展运算符确实能省不少事,C#里虽然没有原生支持,但除了你提到的逐个复制和反射+ExpandoObject,还有几个实用的思路可以试试:
使用AutoMapper等映射库(适合中大型项目)
这类库可以帮你自动处理属性映射,还能灵活添加额外字段。先配置好源对象和目标匿名类型的映射,之后就能一键复制属性并附加新字段:// 第一步:配置AutoMapper(建议放在项目启动逻辑里) var mapperConfig = new MapperConfiguration(cfg => { cfg.CreateMap<YourSourceItem, dynamic>() .ForMember(dest => dest.Extra, opt => opt.MapFrom(_ => "additional property")); }); var mapper = mapperConfig.CreateMapper(); // 第二步:在LINQ中使用 var result = items.Select(item => mapper.Map<dynamic>(item));如果你想更明确地控制匿名类型的结构,也可以先定义一个匿名模板,让AutoMapper直接映射到该类型:
var anonTemplate = new { Prop1 = "", Prop2 = 0, Extra = "" }; var result = items.Select(item => mapper.Map(anonTemplate, item));利用解构语法简化属性提取(C# 7.0+支持)
给你的源对象添加解构方法,就能一次性取出所有属性,不用逐个写:// 给源类添加解构方法 public class YourSourceItem { public string Prop1 { get; set; } public int Prop2 { get; set; } public void Deconstruct(out string prop1, out int prop2) { prop1 = Prop1; prop2 = Prop2; } } // 使用解构创建匿名对象 var result = items.Select(item => { var (prop1, prop2) = item; return new { prop1, prop2, Extra = "additional property" }; });这种方式比手动逐个写属性清爽很多,而且类型安全。
用记录类型(Record)搭配解构/With表达式(C# 9.0+支持)
如果你的源对象是记录类型,解构会更方便;要是可以接受返回记录而非匿名对象,还能直接定义带额外字段的记录:// 源记录类型 public record SourceItem(string Prop1, int Prop2); // 带额外字段的目标记录 public record SourceItemWithExtra(string Prop1, int Prop2, string Extra); // 使用解构快速转换 var result = items.Select(item => { var (p1, p2) = item; return new SourceItemWithExtra(p1, p2, "additional property"); });记录类型的不可变性和简洁语法,在需要复用带额外属性的对象时非常实用。
自定义扩展方法实现轻量级属性复制
自己写个简单的扩展方法,自动把源对象的属性复制到匿名对象模板里,不用手动写所有属性:public static class ObjectExtensions { public static T CopyPropsToAnonymous<T>(this object source, T targetTemplate) { var sourceProps = source.GetType().GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); var targetProps = targetTemplate.GetType().GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); foreach (var sourceProp in sourceProps) { var targetProp = targetProps.FirstOrDefault(p => p.Name == sourceProp.Name && p.PropertyType == sourceProp.PropertyType); if (targetProp != null && targetProp.CanWrite) { targetProp.SetValue(targetTemplate, sourceProp.GetValue(source)); } } return targetTemplate; } } // 使用时只需要定义包含所有需要属性的匿名模板 var result = items.Select(item => item.CopyPropsToAnonymous(new { item.Prop1, // 列出属性让编译器推断类型,扩展方法自动赋值 item.Prop2, Extra = "additional property" }));这个方法兼顾了类型安全和便捷性,不用依赖第三方库。
以上几种方案各有适用场景:映射库适合复杂项目的全局映射,解构和记录类型适合现代C#版本的轻量场景,自定义扩展方法则是灵活的轻量级解决方案~
内容的提问来源于stack exchange,提问作者Andrei
相关产品推荐
相关产品推荐

