2014-05-11 134 views
1

我一直在阅读了一下MSDN上的教程,让我的头周围传递通过引用在C#outref并和我遇到下面的代码示例来了:传递通过引用和参考

using System; 

class TheClass 
{ 
    public int x; 
} 

struct TheStruct 
{ 
    public int x; 
} 

class TestClass 
{ 
    public static void structtaker(TheStruct s) 
    { 
     s.x = 5; 
    } 
    public static void classtaker(TheClass c) 
    { 
     c.x = 5; 
    } 
    public static void Main() 
    { 
     TheStruct a = new TheStruct(); 
     TheClass b = new TheClass(); 
     a.x = 1; 
     b.x = 1; 
     structtaker(a); 
     classtaker(b); 
     Console.WriteLine("a.x = {0}", a.x); //prints 1 
     Console.WriteLine("b.x = {0}", b.x); //prints 5 
    } 
} 

从教程的说明到此:

本实施例表明当结构被传递给一个方法中, 副本结构被传递,但是当一个类的实例被传递,参考 是通过。

我完全理解它,但我的问题是,如果引用在C#中传递给参数,为什么他们需要ref如下面的示例所示:

void tearDown(ref myClass a) 
{ 
    a = null; 
} 

MyClass b = new MyClass(); 
this.tearDown(ref b); 
assert(b == null); 
//b is null 

???我认为C在C中是一样的 - 按值传递。

+2

仅仅因为它是一个引用类型,并不意味着它通过引用传递。除非明确使用'ref',否则传递是有价值的。 –

+0

@JeroenVannevel是的,传递是默认值,但传递的值是引用类型的引用。 – MarcinJuraszek

+0

部分'MyClass b = new MyClass();'创建2个内存:引用变量'b'和堆上的匿名实例。引用变量的行为完全像一个值类型(例如'int')。 –

回答

7

在C#中,基本上所有的类都是指针。然而,通过ref/out或不通过就像是将指针传递给指针或指针本身。

当您通过一个类(按照第一个示例)时,将继续对类成员进行任何更改。但是,将参考更改为对象本身将不会产生结果。假设你更换

public static void classtaker(TheClass c) 
{ 
    c.x = 5; 
} 

随着

public static void classtaker(TheClass c) 
{ 
    c = new TheClass(); 
    c.x = 5; 
} 

由于c不是outref参数,则你重新分配本地指针cc本身没有价值。由于您只修改本地c.x,因此在调用此修改后的ClassTaker后,结果将为b.x == 1。现在

,按照你的第二个例子中,由于是ref参数,更改为自己将在呼叫范围可以看出,作为例子,但价值从呼叫去除ref会导致null断言失败。

基本上,ref传递通过什么可以被认为是指针指向你的指针,而调用没有ref/out传递一个复制的指针到你的对象数据。


编辑:

之所以可以在方法范围分配c.X是因为对象c对象X,你会总是得到相同的指针X不管ref的/ out参数与否。相反,ref/out会修改您更改调用作用域所见的值c的能力。

+0

这里是[教程](http://msdn.microsoft.com/en-us/library/aa288471(v = vs.71).aspx)的链接,它显示了结果。谢谢。 – Unheilig

+0

c.X因为X是c对象内的指针而发生变化,无论ref.out与否,都可以从方法范围内进行更改。 ref/out参数只会修改您调用调用范围所看到的c值的能力。我将把它融入到我的回答中 – David

+0

我真的不知道 - 我比代码中的理论和术语更熟悉代码的行为。为了猜测,我认为这是因为在C#中,一半的行为是由对象本身(struct vs class)的定义决定的,而不是人们想要的特定方法或实现(按照C++) – David