何时使用ref vs out
有人问我有一天当他们应该使用参数关键字out
,而不是ref
。 虽然我(我认为)理解ref
和out
关键字之间的区别(以前已经提到过),并且最好的解释似乎是ref
== in
和out
,但是我应该始终如此的一些(假设或代码)示例out
而不是ref
。
由于ref
较为一般,为什么你想用out
? 它只是语法糖吗?
您应该使用out
,除非你需要ref
。
当需要将数据整理到例如另一个过程时,这会产生很大的差异,这可能是昂贵的。 所以当这个方法不使用它的时候,你想避免编组初始值。
除此之外,它还向读者展示了声明或调用的初始值是否相关(并可能保留)或丢弃。
作为次要区别,out参数不需要被初始化。
举例out
:
string a, b;
person.GetBothNames(out a, out b);
其中GetBothNames是一种以原子方式检索两个值的方法,不管a和b如何,该方法都不会更改行为。 如果呼叫前往夏威夷的服务器,将初始值从这里复制到夏威夷是浪费带宽。 使用ref的类似代码片段:
string a = String.Empty, b = String.Empty;
person.GetBothNames(ref a, ref b);
可能会使读者感到困惑,因为它看起来像a和b的初始值是相关的(尽管方法名称表明它们不是)。
ref
示例:
string name = textbox.Text;
bool didModify = validator.SuggestValidName(ref name);
这里初始值与方法有关。
用out表示该参数未被使用,仅设置。 这有助于调用者了解您始终在初始化参数。
另外,ref和out不仅仅是值类型。 它们还允许您重置引用类型在方法内引用的对象。
从语义上讲, ref
是同时提供“in”和“out”功能的,而out
只提供“out”功能。 有一些事情需要考虑:
out
要求接受参数的方法必须在返回之前的某个时刻为变量赋值。 您可以在一些键/值数据存储类(如Dictionary<K,V>
)中找到此模式,其中您具有TryGetValue
等功能。 这个函数接受一个out
参数,该参数保存检索到的值。 调用者传递一个值到这个函数是没有意义的,所以out
被用来保证在调用之后某个值会在变量中,即使它不是“真实的”数据(在TryGetValue
键不存在)。 out
和ref
参数的编组方式不同 此外,请注意,尽管引用类型和值类型的值的性质不同,但应用程序中的每个变量都指向包含值的内存位置 ,即使对于引用类型也是如此。 恰恰相反,对于引用类型,包含在该内存位置中的值是另一个内存位置。 当您将值传递给一个函数(或进行任何其他变量赋值)时,该变量的值将被复制到另一个变量中。 对于值类型,这意味着类型的整个内容被复制。 对于参考类型,这意味着内存位置被复制。 无论哪种方式,它都会创建变量中包含的数据的副本。 唯一真正的相关性是处理分配语义; 当分配变量或按值传递(默认值)时,当对原始变量(或新变量)进行新分配时,它不会影响其他变量。 对于引用类型,是的,对实例所做的更改在双方都可用,但这是因为实际变量只是指向另一个内存位置的指针; 变量的内容 - 内存位置 - 实际上没有改变。
使用ref
关键字传递时,原始变量和函数参数都将实际指向相同的内存位置。 这又一次只影响分配语义。 如果一个新值被分配给一个变量,那么因为另一个指向同一个内存位置,新值将反映在另一侧。