Ref的C#对象

时间:2009-11-08 15:54:47

标签: c# reference

如果使用'Ref'关键字将对象传递给方法,那么在没有ref关键字的情况下传递它会有什么不同?

因为两者都产生相同的结果,所以在将控制权传递回调用对象时对象已被更改。

如:

 class Student
{
    public string Name
    {
        get;
        set;
    }

    public int Age
    {
        get;
        set;
    }
}
class Program
{
    static Student student = new Student();
    static void Main( string[] args )
    {

        student.Age = 30;
        student.Name = "StudentA";

        Console.WriteLine("Original Student: {0}, Age: {1}", student.Name, student.Age);

        SetStudent(ref student);

        Console.WriteLine("Student by Ref {0}, Age{1}", student.Name, student.Age);

        AnotherStudent(student);

        Console.WriteLine("Just Another Student {0}, Age {1}", student.Name, student.Age);
        Console.ReadLine();
    }

    public static void SetStudent( ref Student student )
    {
        student.Age = 16;
        student.Name = "StudentY";
    }

    public static void AnotherStudent( Student studenta )
    {
        if (studenta.Equals(student))
        {
            Console.WriteLine("The same object in memory");
        }
        studenta.Age = 12;
        studenta.Name = "StudentX";
    }
}

当学生对象传递给AnotherStudent()时,它会被改变,事件认为它没有被'Ref'传递。

有人能解释一下这里发生了什么吗?

修改

那么在函数中将指针传递给C ++中的对象有什么区别?

8 个答案:

答案 0 :(得分:6)

通过引用传递允许方法更改传递给方法的参数的值 - 因此对于引用类型,允许它更改变量的值以引用不同的对象。这是一个例子:

using System;
using System.Text;

class Test    
{    
    static void PassByValue(StringBuilder x)
    {
        x.Append(" - Modified object in method");
        x = new StringBuilder("New StringBuilder object");
    }

    static void PassByReference(ref StringBuilder x)
    {
        x.Append(" - Modified object in method");
        x = new StringBuilder("New StringBuilder object");
    }

    static void Main()
    {
        StringBuilder builder = new StringBuilder("Original");
        PassByValue(builder);
        Console.WriteLine(builder);

        builder = new StringBuilder("Original");
        PassByReference(ref builder);
        Console.WriteLine(builder);
    }
}

在这两种情况下,原始StringBuilder都修改了其内容,然后为参数分配了一个新值。在“按值传递”的情况下,这不会更改builderMain变量的值。在“按引用传递”的情况下,builder的值是指新StringBuilder,因此结果为:

Original - Modified object in method
New StringBuilder object

在您的情况下,您在使用ref时没有看到任何差异,因为您没有更改参数本身的值 - 仅更改其引用的对象中的数据。

有关详细信息,请参阅我的article on parameter passing

答案 1 :(得分:3)

尝试重新分配学生对象,而不是设置它的属性。

public static void SetStudent( ref Student student )
{
    student = new Student();
    student.Age = 16;
    student.Name = "StudentY";
}

public static void AnotherStudent( Student studenta )
{
    studenta = new Student();
    studenta.Age = 12;
    studenta.Name = "StudentX";
}

不要将ref视为“通过引用传递”,因为所有引用类型都是通过引用传递的。可以把它想象成“可以重新分配对此对象的引用”

答案 2 :(得分:2)

尝试将两种学生方法更改为:

public static void SetStudent( ref Student student )
{
    student = new Student();
    student.Age = 16;
    student.Name = "StudentY";
}

public static void AnotherStudent( Student studenta )
{
    studenta = new Student();
    studenta.Age = 12;
    studenta.Name = "StudentX";
}

SetStudent的调用现在将更改您的静态学生变量以引用新实例,因为它是作为ref传递的。对AnotherStudent的调用不会更改参考。

答案 3 :(得分:2)

我将讨论限制为引用类型(类的所有内容,这意味着我不是在谈论结构或内置值类型)。有关完整且更详细的讨论,请参阅this link here

如果您传递没有ref关键字的引用类型,则按值传递引用,这意味着您的引用副本将会生成。此时,您可以修改ref指向的对象,如果您交换另一个对象,则 (指定您在其他对象中传递的ref对象),当函数返回原始< strong>生成在您传入的函数之外的对象仍然指向相同的旧引用

如果您使用ref关键字传递引用类型,则可以使用其他内容交换您传入的对象,因为该引用不仅仅是被复制 - 变量本身正在将以肉体和骨骼传递给函数来做任何事情,你甚至可以指向内存中的其他地址(实例化另一个对象并将其分配给你的ref参数)。

正如您所指出的,在这两种情况下您都可以修改对象。基本上在C#中通过引用传递对应于在C ++中传递一个简单的指针,而没有ref关键字的传递对应于在C ++中传递一个常量指针(你可以进行更改但不能指向smt)。

答案 4 :(得分:1)

通过引用传递变量并传递引用类型是两回事。您可以通过引用传递引用类型来组合它们。

通过引用传递变量只是意味着该方法可以更改变量。该方法可以访问变量本身,而不仅仅是值的副本。变量不必是通过引用传递的引用类型。使用引用传递的少数情况实际上主要是值类型。

通过引用传递引用类型时,这意味着该方法可以访问引用变量,而不仅仅是对象引用的副本。该方法不仅可以访问对象,还可以使用对不同对象的引用替换变量中的引用。

很少需要通过引用传递,当然不是因为您将引用类型作为参数传递而需要执行的操作。

答案 5 :(得分:0)

使用ref关键字将对象传递给方法时,被调用的方法可以更新引用本身,而不仅仅是对象。这意味着在以下代码段中:

object a = new object();
SomeMethod(ref a);

... a可能是调用之后的另一个对象实例,而不是调用之前的对象实例。如果传递一个没有 ref关键字的对象,则被调用的方法可以更新传递对象的属性和成员,但不能将对象本身替换为另一个实例。

答案 6 :(得分:0)

当你这样做时,真正的区别将变得明显......

public static void SetStudent( ref Student student )
{
    student = new Student { Age = 69, Name="Botox" };
}
...
var a = new Student()
var b = a;
SetStudent(ref a);
object.ReferenceEquals(a, b) // Should be false

答案 7 :(得分:0)

这些例子说明了差异

methodA(ref object a)
{
      a = new object();
}

 methodB(object a)
{
     a = new object();
}

object c = new object();
methodA(ref c); //now c points to an entire new object
methodB(c); // does not change the value of c