将数组传递给带或不带ref关键字的函数

时间:2012-11-30 21:58:24

标签: .net arrays parameters

我正在尝试使用传递给.NET中的函数的数组做一些事情,我有点困惑。数组是引用类型,因此对传递给函数的数组所做的更改在函数外部是可见的。示例

static void Main(string[] args)
{
    byte[] arr = new byte[] { 1,2, 3, 4, 5 };    
    Console.WriteLine(string.Join("", arr));        //console output: 12345
    doSomething(arr);
    Console.WriteLine(string.Join("", arr));        //console output: 52341
}
static void doSomething(byte[] array)
{
    byte tmp = array[0];
    array[0] = array[array.Length - 1];
    array[array.Length - 1] = tmp;
}

所以它与使用“ref”关键字(相同的控制台输出)完全相同

doSomething(ref arr);  for static void doSomething(ref byte[] array)

但是,如果我在我的函数中添加以下行:

array = (new byte[] { 1 }).Concat(array).ToArray(); //size of array is changed

结果不同:

12345
52341// "ref" keyword is not used

12345
152341 "ref" keyword is used

有人可以解释一下为什么结果会有所不同吗?

2 个答案:

答案 0 :(得分:2)

值类型变量是包含值的变量。 arr是指向内存中byte []实例的对象变量。当你通过值传递给方法doSomething时,你传递一个指向内存中byte []实例的指针。这样,arr和array都指向内存中byte []的相同实例。如果DoSomething改变了byte []的实例,arr和array都指向它,它实际上并没有改变变量arr,因为它仍然指向内存中的相同位置。但是,由于arr仍然指向内存中的相同位置并且该位置的实例已更新,因此arr可以“看到”更改。

当你调用Concat时,它会在内存中的其他地方生成一个新的byte []实例,并将变量数组添加到内存中的新实例中。字节[]的旧实例仍然存在,而arr仍然指向它。

当您通过ref传递变量 arr 时,对 array 指向的位置的任何更改也会影响 arr 的位置指点。当它没有被ref 传递时,DoSomething 只能更改 arr 指向的内存中byte []的实例,但它不能改变 arr 指着。

这就是为什么在按引用传递对象和按值传递对象之间存在差异。

答案 1 :(得分:0)

对于在没有Ref关键字的方法中传递的任何参数 - 创建局部变量并表示原始参数的副本。因此,当您传入引用类型变量arr时 - 这实际上是Int32引用,它指向某个地址,例如ADDR。然后在方法中创建此变量的副本,该变量完全不受原始参数(arr)的约束。但仍然指向内存中的相同地址,您仍然可以更改基础原始数据。当您通过分配= new ...更改参考值本身时,参考值的本地副本已更改,但此更改不会影响方法中传递的原始引用。

如果您要“绑定”原始引用和new()方法中创建的新引用 - 请使用Ref,指定Ref您说“我想通过引用/引用“。

以下行:

array = (new byte[] { 1 }).Concat(array).ToArray();
  • 如果Ref参数:引用已更改但由于它是通过引用传递的(Ref) - 原始引用也会受到影响
  • 如果默认参数传递:引用的本地副本已更改但原始版本不受影响,因此您获得了一个指向新创建的数组的新引用