为什么我可以在不指定“ref”的情况下从方法更改结构体的 int[] 属性?
从方法中,我可以传递一个包含整数数组的结构,并更改数组中的值。我不确定我是否完全理解为什么我可以这样做。有人可以解释一下为什么我可以更改 int[] 中存储的值吗?
private void DoIt(){
SearchInfo a = new SearchInfo();
a.Index = 1;
a.Map = new int[] { 1 };
SearchInfo b = new SearchInfo();
b.Index = 1;
b.Map = new int[] { 1 };
ModifyA(a);
ModifyB(ref b);
Debug.Assert(a.Index == 1);
Debug.Assert(a.Map[0] == 1, "why did this change?");
Debug.Assert(b.Index == 99);
Debug.Assert(b.Map[0] == 99);
}
void ModifyA(SearchInfo a) {
a.Index = 99;
a.Map[0] = 99;
}
void ModifyB(ref SearchInfo b) {
b.Index = 99;
b.Map[0] = 99;
}
struct SearchInfo {
public int[] Map;
public int Index;
}
From a method, I can pass a struct which contains an array of integers, and change the values in the array. I am not sure I understand fully why I can do this. Can someone please explain why I can change the values stored in the int[]?
private void DoIt(){
SearchInfo a = new SearchInfo();
a.Index = 1;
a.Map = new int[] { 1 };
SearchInfo b = new SearchInfo();
b.Index = 1;
b.Map = new int[] { 1 };
ModifyA(a);
ModifyB(ref b);
Debug.Assert(a.Index == 1);
Debug.Assert(a.Map[0] == 1, "why did this change?");
Debug.Assert(b.Index == 99);
Debug.Assert(b.Map[0] == 99);
}
void ModifyA(SearchInfo a) {
a.Index = 99;
a.Map[0] = 99;
}
void ModifyB(ref SearchInfo b) {
b.Index = 99;
b.Map[0] = 99;
}
struct SearchInfo {
public int[] Map;
public int Index;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
在 C# 中,引用是按值传递的。数组在传递给方法或存储在另一个类的实例中时不会被复制。 - 传递对数组的引用。这意味着接收数组引用(直接或作为另一个对象的一部分)的方法可以修改该数组的元素。
与 C++ 等语言不同,您不能在 C# 中声明“不可变”数组 - 但是您可以使用 List 等具有只读包装器的类来防止对集合的修改。
In C#, references are passed by value. An array is not copied when passed to method or when stored in an instance of another class. - a reference to the array is passed. This means a method which recieves a reference to an array (either directly or as part of another object) can modify the elements of that array.
Unlike languages like C++, you cannot declare "immutable" arrays in C# - you can however uses classes like List which have readonly wrappers available to prevent modification to the collection.
数组被定义为变量的集合。
根据定义,变量可以更改。这就是为什么我们称它们为“变量”。
因此,当你传递一个数组时,你可以改变它的内容;数组的内容是变量。
请记住,正如我们之前在另一个问题中讨论的那样,您可以使用 ref 为变量创建别名。这就是“ref”的用途——为变量创建别名。 (不幸的是,关键字是令人困惑的“ref”——将其设为“别名”可能会更清楚。)
An array is defined as a collection of variables.
Variables, by definition, can be changed. That is why we call them "variables".
Therefore when you pass an array, you can change the contents; the contents of an array are variables.
Remember, as we discussed before in a different question, you use ref to make an alias to a variable. That is what "ref" is for -- making aliases to variables. (It is unfortunate that the keyword is the confusing "ref" -- it probably would have been more clear to make it "alias".)
来自 MSDN:
不要返回数组的内部实例。这允许调用代码来更改数组。以下示例演示了如何通过访问 Path 属性的任何代码来更改数组 badChars,即使该属性未实现 set 访问器也是如此。
您无法通过将 badChars 数组设为只读(在 Visual Basic 中为 ReadOnly)来更正上例中的问题。您可以克隆 badChars 数组并返回副本,但这会对性能产生重大影响。
From MSDN:
Do not return an internal instance of an array. This allows calling code to change the array. The following example demonstrates how the array badChars can be changed by any code that accesses the Path property even though the property does not implement the set accessor.
You cannot correct the problem in the preceding example by making the badChars array readonly (ReadOnly in Visual Basic). You can clone the badChars array and return the copy, but this has significant performance implications.
尽管您的
SearchInfo
结构体是值类型,但.Map
字段保存着引用,因为 Array 是引用类型。将此引用视为指向数组所在内存位置的地址。如您所知,当您将
SearchInfo
实例传递给方法时,SearchInfo
会被复制。并且副本自然包含指向同一数组的完全相同的地址。换句话说,复制结构体并不会复制数组,而只是复制指针。
Although your
SearchInfo
struct is a value type, the.Map
field is holding a reference, because Array is a reference type. Think of this reference as the address pointing to the memory location where the array resides.When you pass an instance of
SearchInfo
to a method, as you know, theSearchInfo
gets copied. And the copy naturally contains the very same address pointing to the very same array.In other words, copying the struct doesn't make a copy of the array, it just makes a copy of the pointer.
嗯,无论如何,它都是通过引用传递的,就像 C# 中的所有引用类型一样。
不幸的是,C# 和 CLR 都不支持常量,因此平台并不真正知道是否允许您更改它。因此,它具有引用,它可以使用它来更改值,并且没有什么可以阻止它这样做。
顺便说一句,您可能会将其视为语言设计错误。这对用户来说是意想不到的。
Well, it is passed by reference anyway, like all reference types in C#.
Neither C# nor CLR support constness, unfortunately, so the platform doesn't really know if you are allowed to change it or not. So, it has the reference, it may use it to change the value, and there's nothing to stop it from doing so.
You may see it as a language design bug, btw. It is unexpected for the user.