前几天有人问我他们什么时候应该使用参数关键字out而不是ref。虽然我(我认为)理解ref和out关键字之间的区别(之前已经问过了),最好的解释似乎是ref == in和out,有什么(假设或代码)的例子,我应该总是使用out而不是ref。
既然ref更通用,为什么还要用out呢?它只是语法上的糖吗?
前几天有人问我他们什么时候应该使用参数关键字out而不是ref。虽然我(我认为)理解ref和out关键字之间的区别(之前已经问过了),最好的解释似乎是ref == in和out,有什么(假设或代码)的例子,我应该总是使用out而不是ref。
既然ref更通用,为什么还要用out呢?它只是语法上的糖吗?
当前回答
只是在OP的注释中澄清一下,对ref和out的使用是“对在方法外部声明的值类型或结构的引用”,这已经在incorrect中建立了。
考虑在StringBuilder上使用ref,它是一种引用类型:
private void Nullify(StringBuilder sb, string message)
{
sb.Append(message);
sb = null;
}
// -- snip --
StringBuilder sb = new StringBuilder();
string message = "Hi Guy";
Nullify(sb, message);
System.Console.WriteLine(sb.ToString());
// Output
// Hi Guy
与此相反:
private void Nullify(ref StringBuilder sb, string message)
{
sb.Append(message);
sb = null;
}
// -- snip --
StringBuilder sb = new StringBuilder();
string message = "Hi Guy";
Nullify(ref sb, message);
System.Console.WriteLine(sb.ToString());
// Output
// NullReferenceException
其他回答
关于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的新特性。
在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语句。
你是正确的,在语义上,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?
让其他人知道当变量从被调用的方法返回时将被初始化!
如上所述: 对于out形参,调用方法需要在方法返回之前赋值。
例子:
Car car;
SetUpCar(out car);
car.drive(); // You know car is initialized.
还是觉得需要好好总结一下,这就是我想出来的。
总结,
当我们在函数内部时,这就是我们如何指定变量数据访问控制,
in = R
out = W必须在R之前
参考 = R+W
解释,
in
函数只能读取该变量。
out
变量不能先初始化,因为, 函数必须先写后读。
ref
函数可以读/写该变量。
为什么要这样命名呢?
关注数据被修改的地方,
in
数据必须在输入(in)函数之前设置。
out
数据必须只在离开(out)函数之前设置。
ref
在输入函数之前必须设置数据。 在离开(out)函数之前可以设置数据。