Dynamics 365 CRM插件C#代码:循环创建Task始终传递首个数据问题
问题排查与修复
核心问题分析
你的代码存在两个关键的引用类型复用问题,导致所有Task最终提交的是同一份数据:
HeadersAndData未创建新实例:HeadersAndData newHeadersAndData = headersAndData;只是复制了原对象的引用,而非创建新对象。所有循环迭代都在修改同一个headersAndData实例的data属性,最终所有Task都会使用最后一次修改后的对象状态。PubconMessage共享同一实例:传入的message是引用类型,每次循环修改message.AddHeadersAndData时,所有Task都会共享这个message实例的最新状态,无法实现每条数据对应独立的消息。- 闭包捕获风险:
Task.Run的lambda表达式捕获的是变量引用而非当前值,若循环执行速度快于Task启动,可能导致多个Task捕获到同一变量的最终状态。
修复后的代码
public void SubmitPubconDataByCreatingTask(HeadersAndData headersAndData, PubconMessage message) { string mainLabel = "exampleLabel"; PubconService pubconService = new PubconService(appSetting.PunconUrl, tracingService); List<Task> submissionTasks = new List<Task>(); foreach (List<object> item in headersAndData.data[mainLabel]) { // 创建HeadersAndData的新实例,避免共享原引用 HeadersAndData newHeadersAndData = new HeadersAndData(); // 复制原headersAndData的所有属性,需根据实际类结构实现深/浅拷贝 newHeadersAndData.data = new Dictionary<string, List<List<object>>>(headersAndData.data); // 创建单条数据列表并替换对应标签的数据 List<List<object>> newSingleList = new List<List<object>> { item }; newHeadersAndData.data[mainLabel] = newSingleList; // 创建PubconMessage的新实例,避免修改原传入的message PubconMessage newMessage = new PubconMessage(); // 复制原message的其他属性(如消息头、配置等,根据实际类结构补充) // newMessage.SomeProperty = message.SomeProperty; newMessage.AddHeadersAndData = newHeadersAndData; // 创建独立的PubconBody实例 PubconBody newPubconBody = new PubconBody(); newPubconBody.AddMessage(newMessage); // 捕获当前迭代的独立变量,避免闭包问题 var currentPubconBody = newPubconBody; Task task = Task.Run(() => pubconService.SubmitData(currentPubconBody)); submissionTasks.Add(task); } Task.WaitAll(submissionTasks.ToArray()); }
关键修复点说明
- 独立实例化
HeadersAndData:通过新建对象并复制原对象属性(按需实现深/浅拷贝),确保每个Task使用独立的数据容器。 - 独立实例化
PubconMessage:避免修改传入的原message,每个迭代生成独立的消息对象,保证每条数据对应专属的消息配置。 - 规避闭包捕获问题:将
newPubconBody赋值给局部变量currentPubconBody后再传入lambda,避免循环变量引用导致的状态覆盖。 - 修正标签变量笔误:原代码中
mainQueryLabel未定义,替换为已声明的mainLabel(若业务有其他标签需求,可自行调整)。
内容的提问来源于stack exchange,提问作者Roshan Shrestha
相关产品推荐
相关产品推荐

