也许这对我来说有点天真,但我似乎无法找到/想到“通过引用传递”的体面用例。更改不可变字符串(正如其他一些Q / As所提到的)通常是可以避免的,返回多个变量通常可以通过返回元组,列表,数组等来更好地处理。
example on MSDN在我看来很糟糕;我只是在Square
方法中返回一个值,而不是将其声明为void
。
在我看来,它似乎是C#的遗留部分,而不是它的一个组成部分。有人比我更聪明,试图解释为什么它仍然存在和/或一些实际可行的实际用例(即几乎在每种情况下都可以避免更改不可变字符串)。
答案 0 :(得分:6)
P.S。:我跟进了@KallDrexx和@newacct的一些评论。我现在看到他们是对的,我错了:我的回答有点误导。优秀的article "Java is pass-by-value, dammit!" by Scott Stanchfield(特定于Java,但仍然与C#最相关)终于让我信服。
我会把我的回答的误导性内容留下来 现在,但可能会在以后删除它们。
通过引用传递不仅仅与 ref
或out
参数一起使用。更重要的是,所有引用类型都通过引用传递(因此它们的名称),尽管这是透明的。
以下是三个 频繁 用例,用于传递引用:
防止在传递大struct
时复制<{1}} 。想象一下,你有一个 值包含的某些byte[]
数组,表示一个二进制大对象(BLOB),可能是几兆字节的struct
类型很多领域。该类型的值可能会占用大量内存。现在您要将此值传递给某个方法。你真的想按值传递它,即创建一个临时副本吗?
您可以通过ref
传递大型结构来避免不必要的复制。
(幸运的是, < / p>
byte[]
等数组是引用类型,因此数组的内容已经通过refence传递。)
通常建议(例如在Microsoft's Framework Design Guidelines中)具有值类型语义的类型如果超过特定大小(32字节)则应实现为引用类型,因此该用例不应非常频繁。
<强>可变性即可。如果您希望某个方法能够改变传递给它的struct
值,并且您希望调用者观察该对象的版本的变异,那么您需要通过引用传递({{1} })。如果值通过值传递给方法,则它会收到一个副本;改变副本将使原始对象保持不变。
在上面链接的框架设计指南文章中也提到了这一点。
请注意针对可变值类型的广泛推荐(参见例如"Why are mutable structs evil?")。您很少需要将ref
或ref
参数与值类型一起使用。
COM互操作通常要求您声明out
和ref
参数。
答案 1 :(得分:4)
假设您想要一个改变值的函数(注意,值,而不是对象),并且您还希望该函数返回一些成功指标。一个好的做法是返回一个表示成功/失败的布尔值,但值是什么?所以你使用ref
:
bool Mutate(ref int val)
{
if(val > 0)
{
val = val * 2;
return true;
}
return false;
}
答案 2 :(得分:3)
在C#中通常有ref
和out
的替代方法 - 例如,如果要向调用者返回多个值,则可以返回元组或自定义输入或接收引用类型作为参数并更改其中的多个值。
但是,在interop:
等情况下,这些关键字仍然是一种方便的解决方案// C
int DoSomething(int input, int *output);
// C#
[DllImport(...)]
static extern int DoSomething(int input, ref int output);
答案 3 :(得分:0)
从功能的角度来看,确实只有少数情况下显式参考参数是有用的。
我见过的一个例子:
public static void Swap<T>(ref T a, ref T b)
{
var temp = a;
a = b;
b = temp;
}
这种方法在某些排序算法中很有用,例如。
有时使用ref参数的一个原因是作为优化技术。有时会通过ref传递一个大型结构(值类型),即使被调用的方法无意修改结构的值,也避免复制结构内容。您可能会认为大型结构最好是一个类(即引用类型),但是当您保留大型此类对象(例如图形处理)时,这会有缺点。作为一种优化,这种技术不会提高代码的可读性,但在某些情况下可以提高性能。
可以询问有关指针的类似问题。 C#通过unsafe
和fixed
关键字支持指针。从功能的角度来看,几乎不需要它们:我无法真正想到一个在没有使用指针的情况下无法编码的函数。但指针不是用来使语言更具表现力,或者代码更具可读性,它们被用作低级优化技术。
事实上,通过引用传递结构实际上是一种传递指向结构数据的指针的安全方法,这是一种典型的大型结构的低级优化技术。
是否支持低级优化功能的旧功能?这可能取决于您的观点,但您不是唯一的C#用户。他们中的许多人会告诉你,指针和其他低级构造的可用性是C#相对于其他语言的一大优势。我不认为参数是遗留特征,它们是语言的组成部分,在某些情况下很有用。
这并不意味着您必须使用ref参数,就像您不必使用LINQ,async / await或任何其他语言功能一样。当你确实需要它时,请为它感到高兴。