【问题标题】:passing array to function with or without ref keyword使用或不使用 ref 关键字将数组传递给函数
【发布时间】:2012-11-19 04:18:52
【问题描述】:

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

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

【问题讨论】:

标签: .net arrays parameters


【解决方案1】:

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

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

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

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

【讨论】:

  • 谢谢,这似乎很合乎逻辑,我想我有点困惑,因为值和引用类型。只是为了确保我理解 - 值类型可以作为值(例如 4)和使用“ref”作为引用(例如“种类”指针放置在放置 4 的内存中) - 引用类型(例如,数组,类)可以作为对它的引用传递(例如“种类”指针,以放置在放置数组/类的内存中)或作为对引用的引用
【解决方案2】:

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

如果您想“绑定”原始引用和 new() 在方法中创建的新引用 - 使用 Ref,通过指定 Ref 您是在说“我想通过引用传递引用” .

在以下行之后:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-31
    • 2020-10-17
    • 2020-08-17
    • 2013-06-29
    • 2016-02-22
    相关资源
    最近更新 更多