我应该如何按值传递数组? Clone() 不气馁吗?

Posted

技术标签:

【中文标题】我应该如何按值传递数组? Clone() 不气馁吗?【英文标题】:How should I pass an array by value? Isn't Clone() discouraged? 【发布时间】:2012-01-09 09:38:56 【问题描述】:

我一直在调试我的一个 C# 程序,经过几次无果而终后,发现错误来自“意外”通过引用而不是值传递数组。

这是一些伪代码:

//1st pass
currentVertices = levels[0].vertices;   
currentVertices[0].Position.Z -= 10;

//2nd pass
currentVertices = levels[1].vertices;
currentVertices[0].Position.Z -= 10;

//3rd pass
currentVertices = levels[0].vertices;
currentVertices[0].Position.Z -= 10;  

//currentVertices[0].Position.Z is now 10 less than expected;
//20 less than it started. Further loops will increase the difference in expected
//value.

我没想到会通过引用传递数组,但我还是不小心这样做了。

有没有办法通过 value 而不是通过引用来分配数组?我知道我可以遍历两个数组,分别分配每个术语,但这似乎不必要地复杂。我有理由确定 Clone() 函数,嗯,克隆,没有相应引用的值,但这是按值分配的唯一方法吗? IE。 currentVertices = levels[1].vertices.Clone();

Clone() 通常不被劝阻吗?按值传递数组的最佳做法是什么?

在短期内,我只是硬编码了加载后的值。

As one of my moderator friends remarked,

“我看到你通过by-pass-reference解决了pass-by-reference。”

【问题讨论】:

我看到您正在尝试按值传递数组。你应该完全放弃它并使用 jQuery。 “Clone() 通常不被劝阻吗?”据我所见,一般推荐 你对这一切的理解似乎奇怪地倒退了。 有人可以解释他们的反对意见吗?请让我知道有什么不清楚的地方! @Raven Dreamer,我没有投反对票。不清楚的一点是: currentVertices[0].Position.Z - 10;那是一种表达。没有任务。目前还不清楚这如何修改数组中的实例。 【参考方案1】:

嗯,在 C# 中,只有值类型是“按值”传递的。 (这是一种过度简化,但这是一种体面的看待它的方式。)其他一切实际上都是按值传递的引用,这类似于传递指针。 (请注意,这与传递“by ref”不同,后者将允许在调用方法中更新变量。)

你有两个选择:

    重构代码以避免改变数组中的对象 深度克隆阵列

这些大致按照我推荐的顺序。

【讨论】:

“在任何语言中都不存在按值传递数组这样的事情。”在php中,所有的数组都是默认传值的。 @BolClock:我已经删除了,但是你确定在 PHP 中,每次传递一个数组都会被复制? 嗯,不是每次,只在修改或迭代时。 我很确定 Perl 按值传递数组,除非你告诉它传递引用。 在 C++ 中,如果您传递一个 std::array 对象,或者实际上是具有数组成员的任何用户定义类型,您将获得该数组的完整浅表副本(按值传递)。 【参考方案2】:

有没有办法通过值而不是通过引用来分配数组?

没有。引用类型的变量(并且 System.Array 是一个引用类型)引用它们的实例。


在我看来,您希望 vertices 属性为您提供数组的深层副本,而不是原始的。

即使你打电话给Clone, that's a shallow copy。克隆不会复制数组的内容。

如果你必须有一个深拷贝,我推荐序列化。对于这个特定的应用程序来说,这可能有点过头了。

【讨论】:

【参考方案3】:

如果您确实需要将新数组传递给函数,.Clone() 是最快的方法。不过,在这种情况下,我通常会考虑使用 Array.AsReadOnly 来为您的数组提供 Collection 包装器。

正如 MSDN 关于AsReadOnly 所描述的:

为防止对数组进行任何修改,请仅通过此包装器公开数组。

只读集合只是一个带有防止修改集合的包装器的集合;因此,如果对基础集合进行了更改,只读集合会反映这些更改。

此方法是 O(1) 操作。

【讨论】:

想对 AsReadOnly 做任何解释吗? AsReadOnly 不会阻止我增加它的值吗? @RavenDreamer:只读集合是按值传递数组的替代方法。不过,我不知道它是否对你有帮助。 @RavenDreamer 没有; AsReadOnly 适用于集合本身的项目:您不能添加/删除/更改存储在数组中的引用。它与那些项目的成员无关。 AsReadOnly 仍会为您提供对数组的引用(以及数组中的项目)。 AsReadOnly 仅阻止对数组的修改,它不会阻止对数组中的项目的修改。由于您正在修改数组中的项目,因此您会看到与以前相同的行为。

以上是关于我应该如何按值传递数组? Clone() 不气馁吗?的主要内容,如果未能解决你的问题,请参考以下文章

为啥不允许将数组按值传递给 C 和 C++ 中的函数?

Java函数参数是不是总是按值传递数组? [复制]

在lisp中按值传递参数

我应该如何在 jna 中按值从 Java 传递和返回 unsigned int 到 C/C++

如何在 C# 中创建一个包含数组但不使用堆的结构?

在 C# 中,我应该按值传递参数并返回相同的变量,还是按引用传递?