0

我正在尝试将数组传递给 .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

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

4

2 回答 2

2

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

当您调用 Concat 时,它会在内存中的其他位置生成一个新的 byte[] 实例,并将变量数组指向内存中的新实例。byte[] 的旧实例仍然存在,并且 arr 仍然指向它。

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

这就是为什么通过引用传递对象和通过值传递对象之间存在差异的原因。

于 2012-11-30T22:26:01.597 回答
0

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

如果你想“绑定”原始引用和在方法中创建的新引用 by new()-use Ref,通过指定Ref你说“我想通过/传递引用”。

在以下行之后:

array = (new byte[] { 1 }).Concat(array).ToArray();
  • Ref参数的情况下:引用已更改,但由于它是通过引用 ( Ref) 传递的 - 原始引用也会受到影响
  • 在默认参数传递的情况下:引用的本地副本已更改但原始不受影响,因此您获得了指向新创建数组的新引用
于 2012-11-30T22:43:18.600 回答