out 参数修饰符(C# 参考)
out
关键字通过引用传递参数。 它让形参成为实参的别名,这必须是变量。 换而言之,对形参执行的任何操作都是对实参执行的。 它与 ref 关键字相似,只不过 ref
要求在传递之前初始化变量。 它也类似于 in 关键字,只不过 in
不允许通过调用方法来修改参数值。 若要使用 out
参数,方法定义和调用方法均必须显式使用 out
关键字。 例如:
int initializeInMethod;
OutArgExample(out initializeInMethod);
Console.WriteLine(initializeInMethod); // value is now 44
void OutArgExample(out int number)
{
number = 44;
}
注意
out
关键字也可与泛型类型参数结合使用,以指定该类型参数是协变参数。 有关在此上下文中使用 out
关键字的详细信息,请参阅 out(泛型修饰符)。
作为 out
参数传递的变量在方法调用中传递之前不必进行初始化。 但是,被调用的方法需要在返回之前赋一个值。
in
、ref
和 out
关键字不被视为用于重载决议的方法签名的一部分。 因此,如果唯一的不同是一个方法采用 ref
或 in
参数,而另一个方法采用 out
参数,则无法重载这两个方法。 例如,以下代码将不会编译:
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
、in
或 out
参数,而另一个方法采用其他参数,则可以完成重载,如:
class OutOverloadExample
{
public void SampleMethod(int i) { }
public void SampleMethod(out int i) => i = 5;
}
编译器通过将调用站点上的参数修饰符与方法调用中使用的参数修饰符进行匹配,从而选择最佳重载。
属性不是变量,因此不能作为 out
参数传递。
不能将 in
、ref
和 out
关键字用于以下几种方法:
异步方法,通过使用 async 修饰符定义。
迭代器方法,包括 yield return 或
yield break
语句。
此外,扩展方法具有以下限制:
- 不能对扩展方法的第一个参数使用
out
关键字。 - 当参数不是结构或是不被约束为结构的泛型类型时,不能对扩展方法的第一个参数使用
ref
关键字。 - 除非第一个参数是结构,否则不能使用
in
关键字。 即使约束为结构,也不能对任何泛型类型使用in
关键字。
声明 out
参数
使用 out
参数声明方法是返回多个值的经典解决方法。 可以考虑对类似场景使用值元组。 下面的示例使用 out
返回具有单个方法调用的三个变量。 第三个参数分配为 null。 这使得方法可以有选择地返回值。
void Method(out int answer, out string message, out string stillNull)
{
answer = 44;
message = "I've been returned";
stillNull = null;
}
int argNumber;
string argMessage, argDefault;
Method(out argNumber, out argMessage, out argDefault);
Console.WriteLine(argNumber);
Console.WriteLine(argMessage);
Console.WriteLine(argDefault == null);
// The example displays the following output:
// 44
// I've been returned
// True
调用具有 out
参数的方法
必须先在单独的语句中声明变量,然后才能将其作为 out
参数传递。 下面的示例先声明了变量 number
,然后再将它传递给将字符串转换为数字的 Int32.TryParse 方法。
string numberAsString = "1640";
int number;
if (Int32.TryParse(numberAsString, out number))
Console.WriteLine($"Converted '{numberAsString}' to {number}");
else
Console.WriteLine($"Unable to convert '{numberAsString}'");
// The example displays the following output:
// Converted '1640' to 1640
还可以在方法调用的参数列表而不是单独的变量声明中声明 out
变量。 这使得代码更简洁可读,还能防止在方法调用之前无意中向该变量赋值。 下面的示例与上一个示例基本相同,不同之处在于它在对 Int32.TryParse 方法的调用中定义了 number
变量。
string numberAsString = "1640";
if (Int32.TryParse(numberAsString, out int number))
Console.WriteLine($"Converted '{numberAsString}' to {number}");
else
Console.WriteLine($"Unable to convert '{numberAsString}'");
// The example displays the following output:
// Converted '1640' to 1640
在上一个示例中,number
变量被强类型化为 int
。 你也可以声明一个隐式类型本地变量,如以下示例所示。
string numberAsString = "1640";
if (Int32.TryParse(numberAsString, out var number))
Console.WriteLine($"Converted '{numberAsString}' to {number}");
else
Console.WriteLine($"Unable to convert '{numberAsString}'");
// The example displays the following output:
// Converted '1640' to 1640
C# 语言规范
有关详细信息,请参阅 C# 语言规范。 该语言规范是 C# 语法和用法的权威资料。