我应该如何按值传递数组? 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() 不气馁吗?的主要内容,如果未能解决你的问题,请参考以下文章