【问题标题】:Performance/style: Changing an object by reference vs returning a copy in C#性能/风格:通过引用更改对象与在 C# 中返回副本
【发布时间】:2012-08-09 03:41:51
【问题描述】:

首先让我提供上下文:

在 C# 中,传递给方法的对象是通过引用传递的。仅当使用关键字 new 重新实例化传入的对象时,引用才会丢失@

所以,我喜欢做 var obj = Alter(obj)(方法 1) 之类的事情,即我传入一个对象并返回该对象。与执行等效操作相反:Alter(obj) (method 2) 引用对象的更改相同,除了通过引用而不是返回副本。我认为第一个更好,因为如果某些冒失的编码员后来修改代码以使用关键字“new”......现有代码不会烧毁和死亡。

我的问题是方法 1 会比 方法 2 使用更多的内存,还是会导致任何其他性能下降?即这会更频繁地调用 GC 吗?

答案是否定的

【问题讨论】:

  • 不知道你是不是想根据Alter(obj)的具体实现来问这个问题?
  • 不,这是一个普遍的问题。我在方法 1 之后设计了我的代码,因为我认为它更具防御性。我只是想再次确认我没有做破坏性的事情,因为在大多数情况下这是不必要的(但在我看来更好的风格)。
  • 你认为方法1在什么方面更“防御”?
  • 您能否发布一个简短的代码示例来说明您在此处保护的问题?如果我理解正确,那么您会误解在方法中重新设置为新对象的对象引用会发生什么。事实上……如果我理解你的话,你似乎有倒退……所以,我一定不是正确地理解你。
  • @LLL:不……不要。为什么不是这些实例方法?它们只有一个输入,也可以是 this 参考,现在您有了更好的设计和更少的问题。

标签: c# .net performance garbage-collection styles


【解决方案1】:

在 C# 中,传递给方法的对象是通过引用传递的。仅当使用关键字 new 重新实例化传入的对象时,引用才会丢失

不,不,至少默认情况下不是。默认情况下,一切都是按值传递的。碰巧的是,在引用类型的情况下,按值传递的东西是引用。

因此,制作了参考的副本。这也反驳了第二个说法。您可以根据需要重新分配方法参数;您只是在修改副本。这也改变了您问题的含义,因为您继续说...

所以,我喜欢做类似 var obj = Alter(obj)(method 1)... 我认为第一个更好,因为如果某些冒失的编码员后来修改代码以使用关键字“new”。 .. 现有代码不会烧毁。

这种情况不会发生。其次,如果你和那些签入的代码完全不起作用并且他们没有测试过的程序员一起工作,你就会遇到更大的问题。但是,无论如何,在参考副本上“使用new 关键字”是无关紧要的(至少在影响原件方面)。即使你的方法是正确的,这也会过于防御。

我的问题是;如果您的函数仅用于改变其单个输入的状态,那么为什么此方法不是开头类型的实例方法?

【讨论】:

  • 关于引用是值类型的有趣部分。我现在正在寻找代码来公开它。关于变异的部分,好吧,我不知道,因为我或多或少地试图提高我对 .NET 的理解,而不是问一个特定的问题。
  • @LLL:嗯,引用不是值类型,因为它不是从System.ValueType 派生的,但是在传递给函数时会被复制。试试这个:void foo(SomeClass x) { x = new SomeClass(); }。创建SomeType 的实例并将其传递给该函数。请注意,它在调用代码中保持不变。
  • 我认为必须将 x 的范围作为参考做更多的事情,它指向一个新对象而不是被引用的对象......确实如此,但我现在看到它通过了通过一个值,即有第二个指针。谢谢!
【解决方案2】:

C# 从不复制引用类型。如果您将 obj 传递给您的方法,然后将其返回,那与您开始使用的对象实例完全相同。

这不会给 GC 带来额外的压力。

【讨论】:

  • 从较低级别..假设对象的内存地址只是被复制到自身上是否安全?或者 CLR 会优化这个吗?
  • 您对完全相同的内存句柄有一个或多个别名。句柄是内存地址之上的一个间接级别。这种额外的间接级别允许 GC 移动内存(如果没有显式固定)以减少堆碎片。
【解决方案3】:

一般来说,不修改指定为方法输入的参数会更安全。至于性能,这两者之间的内存消耗差异几乎可以忽略不计,绝对不会成为您程序的性能瓶颈。这是一个未成熟优化的案例。

您应该选择更清洁、更安全的解决方案,除非您有证据表明性能差异导致您的程序出现问题。

【讨论】:

    猜你喜欢
    • 2017-10-01
    • 1970-01-01
    • 2011-05-09
    • 1970-01-01
    • 2011-01-21
    • 2012-02-13
    • 1970-01-01
    • 1970-01-01
    • 2010-09-13
    相关资源
    最近更新 更多