C# LINQ如何合并两次Select操作为单次以提升执行性能
C# 合并LINQ两次Select操作实现性能优化
场景说明
基于CloudNative.CloudEvents NuGet包处理云原生事件,输入参数为Cosmos DB Trigger传入的IReadOnlyList类型数据,原有实现使用两次连续的Select做投影转换,需要合并为单次执行以降低枚举开销、提升性能。
原有实现代码
核心LINQ转换逻辑
var orderEvents = input .Select(_ => new OrderDocument(_.Id, _.ToString()).ToOrderEvent()) .Select(_ => new CloudEvent() { Type = _.EventType, Subject = _.Subject, Source = _.Source, Data = _ });
关联类定义
OrderDocument
public class OrderDocument { public string Id { get; private set; } public string Json { get; private set; } public OrderDocument(string id, string json) { Id = id; Json = json; } public OrderEvent ToOrderEvent() => OrderEventHelper.ToOrderEvent(Json); }
OrderEventHelper 转换方法
public static OrderEvent ToOrderEvent(string json) { ArgumentHelper.ThrowIfNullOrEmpty(json); var orderEvent = JsonConvert.DeserializeObject<OrderEvent>(json); var eventDefinition = OrderEvents.EventDefinitions.SingleOrDefault(_ => _.EventType == orderEvent.EventType); return eventDefinition == null ? orderEvent : new OrderEvent( orderEvent.Id, orderEvent.Source, orderEvent.EventType, orderEvent.Subject, orderEvent.DataContentType, orderEvent.DataSchema, orderEvent.Timestamp, JsonConvert.DeserializeObject(orderEvent.Payload.ToString(), eventDefinition.PayloadType), orderEvent.TraceId); }
优化方案
两次连续Select会对序列生成两层迭代器,产生额外的枚举开销和中间对象分配,合并时只需要将两次投影的逻辑内联到同一个Select委托中即可,业务逻辑和原有实现完全等价:
var orderEvents = input .Select(_ => { // 原第一次Select逻辑:生成OrderEvent实例 var orderEvent = new OrderDocument(_.Id, _.ToString()).ToOrderEvent(); // 原第二次Select逻辑:映射为CloudEvent实例 return new CloudEvent() { Type = orderEvent.EventType, Subject = orderEvent.Subject, Source = orderEvent.Source, Data = orderEvent }; });
额外优化点
观察现有代码可以发现,OrderDocument实例化后仅调用了ToOrderEvent()方法,而该方法内部完全没有使用OrderDocument的Id属性,属于冗余的临时对象分配,可以直接省略,进一步减少GC压力:
var orderEvents = input .Select(_ => { // 直接调用转换方法,省掉冗余的OrderDocument临时对象 var orderEvent = OrderEventHelper.ToOrderEvent(_.ToString()); return new CloudEvent() { Type = orderEvent.EventType, Subject = orderEvent.Subject, Source = orderEvent.Source, Data = orderEvent }; });
注意:如果后续业务需要使用
OrderDocument的Id属性参与转换逻辑,请勿省略OrderDocument的实例化步骤。
内容的提问来源于stack exchange,提问作者Penguen
相关产品推荐
相关产品推荐

