为什么在方法中反转字符串数组不会持续存在
本文关键字:存在 数组 字符串 方法 为什么 | 更新日期: 2023-09-27 18:09:13
所以我有一个简单的字符串数组。将其传递给一个函数,该函数反转其输入,然后显示数组的内容。我期望数组的内容反转,因为数组是通过引用传递的,但字符串数组没有改变。
string[] words = { "Metal", "Gear", "is", "Awesome!" };
mutateArray(ref words);
foreach (string word in words)
Console.Write(word + " ");
这是我的mutateArray
函数:
public static void mutateArray(ref string[] arr)
{
arr = arr.Reverse().ToArray();
}
我知道,一旦我声明参数必须与关键字ref
一起传递,mutateArray
方法对数组的更改将持续存在。
- 默认情况下不是所有的数组都通过引用传入吗?
- 当涉及关键字ref时,为什么更改持续存在?
- 通过值传递引用类型(
classes
,interfaces
,array
,delegates
)与通过引用(使用关键字ref
)传递它们之间的区别是什么?
这不能像您期望的那样工作的原因是Reverse()实际上并没有反转数组的内容,而是用原始数组的反转内容创建一个新的列表。这就是为什么当你通过引用传递数组时它会工作:然后,你实际上是用mutateArray中创建的新数组替换了调用方法中的整个原始数组。
如果您有一个方法可以在适当的位置进行反转,您可以传入原始数组(不使用ref
),并且在方法调用之后,数组将以相反的顺序排列。
-
c#默认情况下所有参数都是按值传递的。对于像数组这样的引用类型,这意味着引用是按值传递的。
-
ref
使变量通过引用传递给函数。这实际上意味着mutateArray
中的arr
参数是调用方中words
的别名。这就是为什么在mutateArray
退出后,arr
的赋值会导致words
的变化。 -
按值将引用类型传递给函数意味着生成了引用的副本。如果没有
ref
修饰符,mutateArray
中的arr
是一个不同的变量,包含对调用方中的words
相同对象的引用。在这种情况下,分配给arr
对调用方中的words
没有影响。注意,您可以通过共享引用改变数组,但是arr
和words
是单独的存储位置。
-
你混淆了引用类型和引用传递。
ref
关键字可以应用于Value和Reference类型。即使是引用类型,默认情况下也不会通过引用传递。 -
根据MSDN的文档,他们应该。这就是使用
ref
关键字和引用类型的全部目的。 -
不同之处在于,当您通过引用类型传递时,您可以更改原始变量的引用,而不仅仅是方法中的实例。
words是对数组的引用。只需考虑它包含该数组的内存地址。
当你把它作为参数给MutateArray时(没有ref关键字),它的VALUE将被复制到arr中。所以arr和words是不同的变量,但是它们包含相同的值(=内存地址)。这意味着它们指向同一个对象(字符串数组)。
你可以改变对象的内容,但是words(和arr)仍然会引用它。
如果你将arr赋值给一个不同的对象,那么它的值就会改变,所以它将指向一个不同于words的对象。
但是,如果使用ref关键字,则arr和words是同一个变量。这意味着如果你改变了arr的值(=将其赋值给一个新对象),你也改变了words的值,因此words将指向相同的新对象。
也许所有这些在技术上不是100%正确,但这是我喜欢思考的方式,以便理解它是如何工作的。
ref关键字是下面的Swap方法在c#中工作的原因;如果没有它,它只会改变Swap方法的内部变量(基本上什么都不做)
public void Swap<T>(ref T a, ref T b) {
T temp = a;
a = b;
b = temp;
}
你的问题是完全可以理解的,那一刻我也很困惑。
下面是解释
简短的解释- 当你把一个引用类型传递给一个方法并改变它的属性时,方法外的对象可以看到属性的改变,因为对象本身保持不变。
- 当你将引用类型传递给一个方法并对实例本身进行更改时,方法外部的对象无法看到更改,因为在方法内部你基本上开始指向另一个对象。因此,对象在方法内部发生了变化,并作为一个陌生人留在那里。
长解释假设你有一个从数据库中获取值的引用类型实例。
using (var context = new MyAdventureWorksEntities2())
{
Product p = context.Products.Where(item => item.ProductID == 1000).First();
Console.WriteLine(p.Name); // p.Name = "INITIAL NAME"
UpdateName(p);
Console.WriteLine(p.Name);
}
假设你有一个从数据库中获取值的引用类型实例。
using (var context = new MyAdventureWorksEntities2())
{
Product p = context.Products.Where(item => item.ProductID == 1000).First();
Console.WriteLine(p.Name); // p.Name = "INITIAL NAME"
UpdateName(p);
Console.WriteLine(p.Name);
}
这是你的UpdateName
方法:
public static void UpdateName(Product p)
{
p.Name = "UPDATED NAME";
}
这段代码发出如下结果:INITIAL NAME
UPDATED NAME
然而,如果您将方法更改为以下内容:
public static void UpdateName(Product p) { using (var context = new MyAdventureWorksEntities2()) { p = context.Products.Where(item => item.ProductID == 1003).First(); // p.Name = "ANOTHER PRODUCT NAME" } }
你的结果将是:INITIAL NAME
INITIAL NAME
请注意,我根本没有触及ref
关键字。
也许在这些例子之后,简短的描述会更容易理解。