前几天有人问我他们什么时候应该使用参数关键字out而不是ref。虽然我(我认为)理解ref和out关键字之间的区别(之前已经问过了),最好的解释似乎是ref == in和out,有什么(假设或代码)的例子,我应该总是使用out而不是ref。
既然ref更通用,为什么还要用out呢?它只是语法上的糖吗?
前几天有人问我他们什么时候应该使用参数关键字out而不是ref。虽然我(我认为)理解ref和out关键字之间的区别(之前已经问过了),最好的解释似乎是ref == in和out,有什么(假设或代码)的例子,我应该总是使用out而不是ref。
既然ref更通用,为什么还要用out呢?它只是语法上的糖吗?
当前回答
关于c# 7的额外注意事项: 在c# 7中,不需要使用out预先声明变量。代码是这样的:
public void PrintCoordinates(Point p)
{
int x, y; // have to "predeclare"
p.GetCoordinates(out x, out y);
WriteLine($"({x}, {y})");
}
可以这样写:
public void PrintCoordinates(Point p)
{
p.GetCoordinates(out int x, out int y);
WriteLine($"({x}, {y})");
}
来源:c# 7的新特性。
其他回答
作为ref传递的参数必须在传递给方法之前初始化,而out形参在传递给方法之前不需要初始化。
你是正确的,在语义上,ref同时提供“in”和“out”功能,而out只提供“out”功能。有一些事情需要考虑:
out requires that the method accepting the parameter MUST, at some point before returning, assign a value to the variable. You find this pattern in some of the key/value data storage classes like Dictionary<K,V>, where you have functions like TryGetValue. This function takes an out parameter that holds what the value will be if retrieved. It wouldn't make sense for the caller to pass a value into this function, so out is used to guarantee that some value will be in the variable after the call, even if it isn't "real" data (in the case of TryGetValue where the key isn't present). out and ref parameters are marshaled differently when dealing with interop code
Also, as an aside, it's important to note that while reference types and value types differ in the nature of their value, every variable in your application points to a location of memory that holds a value, even for reference types. It just happens that, with reference types, the value contained in that location of memory is another memory location. When you pass values to a function (or do any other variable assignment), the value of that variable is copied into the other variable. For value types, that means that the entire content of the type is copied. For reference types, that means that the memory location is copied. Either way, it does create a copy of the data contained in the variable. The only real relevance that this holds deals with assignment semantics; when assigning a variable or passing by value (the default), when a new assignment is made to the original (or new) variable, it does not affect the other variable. In the case of reference types, yes, changes made to the instance are available on both sides, but that's because the actual variable is just a pointer to another memory location; the content of the variable--the memory location--didn't actually change.
与ref关键字一起传递表示原始变量和函数参数实际上都指向相同的内存位置。同样,这只影响赋值语义。如果将一个新值赋给其中一个变量,那么由于其他变量指向相同的内存位置,新值将反映在另一侧。
读音: Out =只初始化/填充一个参数(参数必须为空),将其plain返回 Ref = reference,标准参数(可能带有value),但函数可以修改它。
可以在两个上下文中使用out上下文关键字(每个上下文都是到详细信息的链接),作为参数修饰符或在接口和委托中的泛型类型参数声明中使用。本主题讨论参数修饰符,但有关泛型类型参数声明的信息,请参阅另一个主题。
out关键字使参数通过引用传递。这类似于ref关键字,只不过ref要求在传递变量之前对其进行初始化。要使用out形参,方法定义和调用方法都必须显式使用out关键字。例如: c#
class OutExample
{
static void Method(out int i)
{
i = 44;
}
static void Main()
{
int value;
Method(out value);
// value is now 44
}
}
虽然作为输出参数传递的变量在传递之前不必初始化,但被调用的方法需要在方法返回之前赋值。
尽管ref和out关键字会导致不同的运行时行为,但它们在编译时不被视为方法签名的一部分。因此,如果唯一的区别是一个方法使用ref参数,而另一个方法使用out参数,则方法不能重载。例如,下面的代码将无法编译: c#
class CS0663_Example
{
// Compiler error CS0663: "Cannot define overloaded
// methods that differ only on ref and out".
public void SampleMethod(out int i) { }
public void SampleMethod(ref int i) { }
}
然而,如果一个方法使用ref或out参数,而另一个方法两者都不使用,则可以进行重载,如下所示: c#
class OutOverloadExample
{
public void SampleMethod(int i) { }
public void SampleMethod(out int i) { i = 5; }
}
属性不是变量,因此不能作为参数传递。
有关传递数组的信息,请参见使用ref和out传递数组(c#编程指南)。
以下类型的方法不能使用ref和out关键字:
Async methods, which you define by using the async modifier.
Iterator methods, which include a yield return or yield break statement.
例子
当您希望一个方法返回多个值时,声明一个out方法非常有用。下面的示例使用out通过一个方法调用返回三个变量。注意,第三个参数被赋值为null。这使得方法可以有选择地返回值。 c#
class OutReturnExample
{
static void Method(out int i, out string s1, out string s2)
{
i = 44;
s1 = "I've been returned";
s2 = null;
}
static void Main()
{
int value;
string str1, str2;
Method(out value, out str1, out str2);
// value is now 44
// str1 is now "I've been returned"
// str2 is (still) null;
}
}
在c#中如何使用in或out或ref ?
All keywords in C# have the same functionality but with some boundaries. in arguments cannot be modified by the called method. ref arguments may be modified. ref must be initialized before being used by caller it can be read and updated in the method. out arguments must be modified by the caller. out arguments must be initialized in the method Variables passed as in arguments must be initialized before being passed in a method call. However, the called method may not assign a value or modify the argument.
以下类型的方法不能使用in、ref和out关键字:
Async方法,通过使用Async修饰符来定义。 迭代器方法,其中包括yield return或yield break语句。