2012-11-30 44 views
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; 
} 

所以它的工作原理完全一样,与(同一控制台输出)

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 

有人能解释我为什么结果不同吗?

+0

[参数传递在C#](http://www.yoda.arachsys.com/csharp/parameters.html#ref) – sll

回答

2

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

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

当通过REF传递变量ARR,然后到阵列指向也会影响其中ARR指向任何变化。当它不通过参考DoSomething只能更改内存中的字节[]的实例,指向,但它不能更改,其中指向。

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

+0

谢谢,这似乎是非常合乎逻辑的,我想我有点困惑,因为价值和参考类型。只是为了确保我理解 - 值类型可以作为值(例如4)传递,并作为参考与“ref”一起使用(例如,“放置在放置4的内存中的”种类“指针) - 引用类型(例如,数组,类)可以作为引用传递给它自我(例如“放置在放置数组/类的内存中的指针类型”)或作为对引用的引用 – user1049522

0

对于在方法中传递的任何参数没有Ref关键字 - 创建的局部变量并代表原始参数的副本。所以当你传入引用类型变量arr时 - 这是真正的Int32引用,指向某个地址,比如ADDR。然后在一个方法中创建这个变量的副本,它与原始参数(arr)完全无关。但仍指向内存中的相同地址,您仍然可以更改基础原始数据。当您通过分配= new ...来更改参考值本身时,参考值的本地副本会发生更改,但此更改不会影响方法中传递的原始参考值。

如果你想“绑定”原件备查,并在方法创建一个新的new() - 使用Ref,通过指定Ref你说“我想通过/传递给参考参考”。

以下线之后:

array = (new byte[] { 1 }).Concat(array).ToArray(); 
  • Ref参数情形:参考改变,但是,因为它是通过引用传递(Ref) - 原始参考的影响以及
  • 在默认参数传递的情况下:本地参考副本被更改,但原始不受影响,因此您获得了指向新创建阵列的新参考号