C# - 引用类型与指针比较的混淆?

3
我正在阅读Jeffrey Richter的CLR via C#,在其中他说通过ref参数传递的引用本身是按值传递的。这对我来说很有意义,也类似于指针。
例如,在C中,如果我将指针传递到函数中,然后通过malloc分配指针,它会将指针更改为指向新的内存位置,但我知道由于指针本身是副本,它不会重新分配传入函数的原始指针。为了在函数外部实现对指针的更改,我必须使用双重指针。
然而,在C#中:
void Swap(ref Object a, ref Object b)
{
    Object t = b;
    b = a;
    a =t ;
}

这表明参考并不是按值传递的,这说明作品。类比上面的malloc,我假设我可以通过引用传递一个对象,并为其分配一个新对象,然后重新赋值将在函数外持续存在。

有人能解决我的困惑吗?

3个回答

6
你的理解有些偏差。在涉及到引用类型时,引用是按值传递的。而通过ref参数传递则不同。
private void Frob(Foo foo) // Foo is a class
{

}

调用站点的类型为Foo的对象的引用副本被传递到方法Frob中。该引用的副本按值传递。该引用和调用站点上的引用指向内存中的同一对象,并将继续这样做,直到它们中的一个指向内存中的其他对象为止。例如,如果在此方法内部编写:

foo = someOtherFoo;

那么,参数不再引用调用站点的相同对象。调用站点的引用是不变的

现在考虑如果我们引入ref关键字。

private void Frob(ref Foo foo)
{
    foo = someOtherFoo;
}

在这种情况下,foo 是调用站点变量的一个 别名。这些变量不仅仅是指向内存中相同的对象,它们就像是同一个变量!因此,将 foo 指向 someOtherFoo 不仅会改变该方法内部的 foo,这个改变也会反映在调用站点上。

谢谢你的回答,我希望我能给Mitch和你们两个人都一个答案。这是一个非常好的描述它如何工作,易于理解。 - Joshua Enfield

5

如果没有使用 ref 关键字,对象的引用将按值传递。

如果使用了 ref 关键字,则会传递一个指向对象引用的引用值。

[实际上编译器隐藏了这样一个事实,即对显式使用 ref 传递的参数进行赋值,会改变指针的值]


在这种情况下,将ref关键字视为C语言中自动管理的双重指针是否合适? - Joshua Enfield

0

当调用时,这会传递原始指针值(引用)

void Swap(ref Object a, ref Object b)
{
    Object t = b;
    b = a;
    a = t;
}

这将传递原始指针的副本:

void Swap(Object a, Object b)
{
    Object t = b;
    b = a;
    a = t;
}

两者都将指向同一对象,但更改第二个对象不会反映在此方法的更大范围内...

我不太明白问题...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接