[英]C# passing parameters by reference
我有下面的代码,它将字符串前缀到字符串数组的每个成员的开头。 即。 以“z”为前缀的[“a”,“b”,“c”]变为[“za”,“zb”,“zc”]。
private string[] Prefix(string[] a, string b) {
for(int i = 0;i < a.Length;i++) {
a[i] = b + a[i];
}
return a;
}
该功能工作正常(虽然如果有更好的方法来做到这一点,我很高兴听到它),但我在传递参数时遇到问题。
string[] s1 = new string[] {"a","b"};
string[] s2 = Prefix(s1,"z");
现在据我所知,我正在通过值传递s1。 但是当前缀函数完成时,s2和s1具有相同的[“za”,“zb”]值,或者s1已经通过引用传递。我确定你必须在c#中明确声明这种行为,并且我很困惑。
正如其他人所说,引用是按值传递的。 这意味着你的s1
引用被复制到a
,但它们仍然引用内存中的同一个对象。 我要做的是修复你的代码是这样写的:
private IEnumerable<string> Prefix(IEnumerable<string> a, string b) {
return a.Select(s => b + s);
}
。
string[] s1 = new string[] {"a","b"};
string[] s2 = Prefix(s1,"z").ToArray();
这不仅可以解决您的问题,而且还允许您使用Lists和其他字符串集合以及简单数组。
这是一个更好的方法:
private string[] Prefix(string[] a, string b) {
return a.Select(s => b + s).ToArray();
}
甚至:
private IEnumerable<string> Prefix(IEnumerable<string> a, string b) {
return a.Select(s => b + s);
}
您正在通过值传递对s1
的引用。 换句话说,您a
参数(在前缀函数范围内)和您的s1
变量是对同一数组的引用。
字符串是不可变的
这意味着当你将一个字符串附加到一个字符串时,你会得到一个全新的字符串 - 出于性能原因。 制作一个重新分配现有阵列的新字符串会更便宜。
因此,为什么你觉得你正在按价值使用字符串
在c#中,所有引用类型都默认通过引用传递 - 即在堆上创建的类而不是值。
传递对象的值。 对于“引用”对象,这是引用的值。 不进行基础数据的克隆/复制/复制。
要解决观察到的问题,只需不要改变输入数组 - 而是创建一个新的输出数组/对象并适当地填充它。 (如果你必须使用数组,我可能会使用这种方法,因为它无论如何都很像C-like。)
或者,您可以首先克隆输入数组(这也会创建一个新对象)。 在这种情况下使用克隆(这是一个浅拷贝)是可以的,因为内部成员(字符串)本身是不可变的 - 即使它们是引用类型,底层对象的值一旦创建就无法更改。 对于嵌套的可变类型,可能需要更加小心。
以下是两种可用于创建浅表副本的方法:
string[] B = (string[])A.Clone();
string[] B = (new List<string>(A)).ToArray();
它没有包容性。
就个人而言,我会使用LINQ。 这是一个预告片:
return a.Select(x => b + x).ToArray();
string
数组的引用 按值传递。 因此,调用方法中的原始数组引用不能更改,这意味着Prefix
方法中的a = new string[10]
对调用方法中的s1
引用没有影响。 但是数组本身是可变的,并且对同一数组的重复引用能够以对同一数组的任何其他引用可见的方式对其进行更改。
实际上,对s1
的引用通过值传递给Prefix()
。 虽然现在有两个不同的引用,但s1
和s2
仍然引用相同的字符串数组,因为数组是C#中的引用类型。
通过价值传递并不意味着你无法改变事物。 对象按值传递,但该值(有效地)是指向对象的指针。 数组是对象,并且传入指向数组的指针。如果在方法中更改数组的内容,则数组将反映更改。 字符串不会发生,因为字符串是不可变的 - 一旦构造,它们的内容就不会改变。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.