【问题标题】:with expression vs new keyword使用表达式与新关键字
【发布时间】:2020-10-06 15:07:00
【问题描述】:

我正在阅读有关“C#9.0 中的新功能”的 devblogs,然后我注意到“带有表达式”。

public data class Person
{
    public string FirstName { get; init; }
    public string LastName { get; init; }
}
var otherPerson = person with { LastName = "Hanselman" };

他们说

一条记录隐含地定义了一个受保护的“复制构造函数”——一个 获取现有记录对象并将其复制字段的构造函数 按字段到新的:

protected Person(Person original) { /* copy all the fields */ } // generated

with 表达式导致复制构造函数被调用,并且 然后在顶部应用对象初始化器来更改属性 相应地。

我的问题是, “with”是否从“Heap”复制整个旧对象,然后用新值(如果存在)修改它们,然后创建新实例? (IMO ...我认为这是一种昂贵的方法) 还是“with”让你只写更少的行而没有任何内存泄漏?

如果我的第一个假设是正确的,最好使用“with”或“new”,例如:var obj = new foo();

【问题讨论】:

  • "然后创建新实例" - 不。不会创建第二个新实例,只会创建第一个修改值的实例。 -- Gareth 的回答是正确的,但并未阐明这一点。
  • 所以“用表达”让班级像商店一样?每次我们声明一个新的 obj 时,它都会转到 Person 并返回一个新的修改过的实例?
  • 每个with 表达式都会从旧实例创建一个新实例。如果您不想额外分配,请不要使用person with {FirstName="John"} with {LastName="Doe"}。做person with {FirstName="John", LastName="Doe"},你只会得到一个分配。

标签: c# heap-memory c#-9.0


【解决方案1】:

with 表达式创建了一个新实例,因此旧实例将保持不变,它不会发生任何变化——这是有道理的,因为其意图是处理不可变数据。

这不是内存泄漏,除非您以某种方式保留旧实例。它可能会增加 GC 流失率,但这不一定是坏事,而且从不变性中获得的易于推理的收益通常值得付出这些代价。

(当然,我假设这里的编译器有优化的潜力,如果编译器可以证明旧值不会被使用,但我怀疑这样的事情是否已实现——但至少)。

编辑:

这里是a SharpLab decompilation(进行了一些更改以使其正常工作)。你可以看到它编译成非常简单的东西。

【讨论】:

  • 简单的判断方法是使用“with”分支模拟一个sharplab示例并检查生成的c#选项卡。我会这样做并提供一个链接,但很难通过手机完成
  • @pinkfloydx33 是的,我正在调查。需要进行一些更改才能使其在 SharpLab 上运行,但我已经添加了它。
  • 感谢SharpLab的反编译,它使答案变得非常清楚。
猜你喜欢
  • 2019-09-14
  • 1970-01-01
  • 1970-01-01
  • 2021-12-04
  • 2017-04-13
  • 1970-01-01
  • 1970-01-01
  • 2011-11-20
  • 2013-05-20
相关资源
最近更新 更多