我有下面的代码,它将字符串前缀到字符串数组的每个成员的开头。即。以“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#中明确声明这种行为,并且我很困惑
答案 0 :(得分:5)
正如其他人所说,引用是按值传递的。这意味着您的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和其他字符串集合以及简单数组。
答案 1 :(得分:3)
答案 2 :(得分:2)
这是一种更好的方法:
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);
}
答案 3 :(得分:1)
您正在按值传递s1
的引用。换句话说,您的a
参数(在前缀函数范围内)和您的s1
变量是对同一数组的引用。
答案 4 :(得分:1)
字符串是不可变的
这意味着当你将一个字符串附加到字符串时,你会得到一个全新的字符串 - 出于性能原因。制作一个重新分配现有阵列的新字符串会更便宜。
因此,为什么感觉你正在按值使用字符串
在c#中,默认情况下,所有引用类型都通过引用传递 - 即在堆上创建的类而不是值。
答案 5 :(得分:1)
传递对象的值。对于“引用”对象,这是引用的值。 未制作基础数据的克隆/复制/副本。
要解决观察到的问题,只需不要改变输入数组 - 而是创建一个新的输出数组/对象并适当地填充它。 (如果你必须使用数组,我可能会使用这种方法,因为它无论如何都很像C-like。)
或者,您可以先克隆输入数组(这也会创建一个新对象)。在这种情况下使用克隆(这是一个浅拷贝)是可以的,因为内部成员(字符串)本身是不可变的 - 即使它们是引用类型,底层对象的值一旦创建就无法更改。对于嵌套的可变类型,可能需要更加小心。
以下是两种可用于创建浅层副本的方法:
string[] B = (string[])A.Clone();
string[] B = (new List<string>(A)).ToArray();
它没有包容性。
就个人而言,我会使用LINQ。这是一个预告片:
return a.Select(x => b + x).ToArray();
答案 6 :(得分:1)
string
数组的引用按值传递。
因此,调用方法中的原始数组引用无法更改,这意味着a = new string[10]
方法中的Prefix
对调用方法中的s1
引用没有影响。但是数组本身是可变的,并且对相同数组的重复引用能够以对其它任何其他引用可见的方式对其进行更改。阵列。
答案 7 :(得分:1)
实际上,对s1
的引用已按值传递给Prefix()
。虽然您现在有两个不同的引用,但s1
和s2
仍然引用相同的字符串数组,因为数组是C#中的引用类型。
答案 8 :(得分:1)
通过价值传递并不意味着你无法改变事物。 对象按值传递,但该值(有效地)是指向对象的指针。 数组是对象,并且传入指向数组的指针。如果在方法中更改数组的内容,则数组将反映更改。 字符串只是因为字符串是不可变的 - 一旦构造,它们的内容就不会改变。