如果使用'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 ++中的对象有什么区别?
贝
答案 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
都修改了其内容,然后为参数分配了一个新值。在“按值传递”的情况下,这不会更改builder
中Main
变量的值。在“按引用传递”的情况下,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