关于.net:在C#中使用’ref’关键字

Use of 'ref' keyword in C#

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicates:
Why use ref keyword when passing an Object?
When to pass ref keyword in

"ref"关键字在c中的正确用法是什么?我相信关于这方面的讨论有很多,但我不清楚的是:

  • 如果传入引用对象,是否需要ref关键字?我的意思是,当您在堆中创建一个对象时,它不是总是通过引用传递的吗?是否必须将其明确标记为引用?

  • 使用ref表示将引用传递给函数。

    默认行为是函数接收到对同一对象的新引用。这意味着,如果更改引用的值(例如,将其设置为新对象),则不再指向原始源对象。当使用ref传递时,更改引用的值会更改源引用,因为它们是相同的。

    考虑一下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public class Thing
    {
        public string Property {get;set;}
    }

    public static void Go(Thing thing)
    {
        thing = new Thing();
        thing.Property ="Changed";
    }

    public static void Go(ref Thing thing)
    {
        thing = new Thing();
        thing.Property ="Changed";
    }

    如果你跑

    1
    2
    3
    4
    5
    6
    7
    var g = new Thing();

    // this will not alter g
    Go(g);

    // this *will* alter g
    Go(ref g);


    这里的答案中有很多令人困惑的错误信息。要理解这一点,最简单的方法是放弃"ref"的意思是"by reference"。更好的方法是,"ref"的意思是"我希望被调用方的这个形参是调用方的一个特定变量的别名"。

    当你说

    1
    2
    3
    4
    void M(ref int y) { y = 123; }
    ...
    int x = 456;
    M(ref x);

    也就是说"在调用m的过程中,被调用方的形参y是调用方变量x的另一个名称"。将123赋给y与将123赋给x完全相同,因为它们是相同的变量,一个具有两个名称的变量。

    这就是全部。不要考虑引用类型或值类型,不要考虑通过引用传递或通过值传递。所有"ref"的意思都是"暂时为这个变量取第二个名称"。


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Diagnostics;

    namespace InOutRef
    {
        static class InOutRef
        {
            public static void In(int i)
            {
                Console.WriteLine(i);
                i=100;
                Console.WriteLine(i);
            }
            public static void Ref(ref int i)
            {
                Console.WriteLine(i);
                i=200;
                Console.WriteLine(i);
            }
            public static void Out(out int i)
            {
                //Console.WriteLine(i); //Error Unsigned Ref
                i=300;
                Console.WriteLine(i);
            }
        }

        class Program
        {
            static void Main(string[] args)
            {
                int i = 1;
                InOutRef.In(i); //passed by value (in only)
                Debug.Assert(i==1);
                InOutRef.Ref(ref i); //passed by ref (in or out)
                Debug.Assert(i == 200);
                InOutRef.Out(out i); //passed by as out ref (out only)
                Debug.Assert(i == 300);
            }
        }
    }

    我的回答再直白不过了。当使用时,代码将不记得经典的Java交换问题之类的参考通道。但是,在使用ref时,它将类似于vb.net,因为它将记住输入和输出的更改。如果使用out参数,则意味着必须在返回之前声明它(这由编译器强制执行)。

    1
    2
    3
    4
    5
    6
    7
    8
    Output:
    1                                  //1 from main
    100                                //100 from in
    1                                  //1 is NOT remembered from In
    200                                //200 from ref
    //should be 200 here but out enforces out param (not printed because commented out)
    300                                //300 is out only
    Press any key to continue . . .

    我相信ref关键字指示您是通过引用而不是通过值传递对象。例如:

    1
    2
    3
    void myfunction(ref object a) {
    a = new Something();
    }

    将更改调用函数中的值然而,

    1
    2
    3
    void myfunction(object a) {
    a = new Something();
    }

    将更改本地的值,但不会在调用函数中更改。您仍然可以更改项的属性,但不能设置项本身的值。例如;a.someproperty=值;

    在这两种情况下都有效。