【问题标题】:C# grouped objects aren't being mutated as expectedC# 分组对象未按预期进行变异
【发布时间】:2022-01-23 07:57:01
【问题描述】:

我有一组对象以IEnumerable 的形式输入一个方法,我按引用属性对它们进行分组,然后逐组处理它们。该处理涉及改变对象的其他属性。当方法完成并返回时,调用者期望它传入的对象集合被改变。整个过程是异步的,方法如下:

public async Task MutateMyObjects(IEnumerable<MyObjects> myObjects,
    CancellationToken cancellationToken)
{
    var myObjectsGroupedByGroupingEntity = myObjects
        .GroupBy(myObject => myObject.GroupingEntity);

    foreach (var myObjectGroup in myObjectsGroupedByGroupingEntity )
    {
        await ProcessGroup(myObjectGroup.Key, myObjectGroup, cancellationToken);
    }
}

MyObjectGroupingEntity 都是类,因此我的期望是 MyObjects 作为引用类型传递,并且变异是整个过程固有的。

实际发生的是MutateMyObjects 的调用者观察到的MyObjects 的属性值与它在方法调用之前观察到的相同。在Task 完成后观察到这些结果。在调试上述方法时,观察方法返回前的变量状态,发现变量myObjectGroup下的对象集合包含了变异的属性,而变量myObjects下的对象集合没有。

我不确定我的理解缺少哪些方面导致我得到错误的期望,任何见解将不胜感激。

【问题讨论】:

  • 你传递给方法的是什么?如果它类似于someList.Select(x =&gt; new MyObjects(x)),那么每次迭代都会创建新对象。你可以将它传递给MutateMyObjects,它会改变它创建的对象,但如果你再次迭代IEnumerable,它会创建全新的未变异对象。
  • IEnumerable&lt;MyObjects&gt; 是否会再次访问您的数据库以获取新数据?
  • @Llama 那是在工作完成之后——这不是我真正的意思——你不能在异步函数中使用 myObj 并在它工作的同时观察它的变化
  • @riffnl 我明白了,我误解了你的评论。
  • @juharr 感谢您的问题,我查看了数据源,这是一个使用 Select 管道传输到映射器的 LINQ to SQL 查询。因此,我通过在映射 Select 之后添加 ToList() 调用来执行查询,现在由于您所描述的,对象突变仍然存在。

标签: c# linq linq-to-objects .net-6.0


【解决方案1】:

问题是我需要先执行 LINQ 查询以实现对象,然后再将它们发送出去进行突变。问题中未显示的是IEnumerable&lt;MyObject&gt; myObjects 的表示方式。在我的例子中,myObjects 是通过管道传输到对象映射中的数据库获取的延迟执行。这意味着当我改变对象时,groupBy 强制初始化对象,这些对象随后在所示方法返回时丢失。当“变异”对象被“使用”时,这些对象实际上被重新初始化了。

正如@Enigmativity 所指出的,在此方法中,签名可能应该要求IList&lt;MyObject&gt; 以确保对象的存在,因为该方法打算改变它们。这意味着该方法的调用者需要在调用该方法之前执行任何 LINQ 查询,从而避免这个陷阱。

【讨论】:

  • 或者如果您捕获了变异对象(返回它们) - 我个人认为 GroupBy 可能触发了数据库查询运行,它被暂时捕获但没有返回。我想如果您远离变异并倾向于以“不可变模式”进行思考,那么您可能会返回它..不过是学习的好日子! ?
  • 可变性和延迟执行可能会导致问题。
猜你喜欢
  • 2022-08-19
  • 2015-01-31
  • 2023-03-15
  • 2021-02-04
  • 2019-03-09
  • 1970-01-01
  • 1970-01-01
  • 2019-07-22
  • 1970-01-01
相关资源
最近更新 更多