C# 语言 ref, out

示例

ref和out关键字导致参数按引用传递,而不是按值传递。对于值类型,这意味着被调用方可以更改变量的值。

int x = 5;
ChangeX(ref x);
// x的值现在可能会不同

对于引用类型,变量中的实例不仅可以被修改(如没有的情况一样ref),还可以被完全替换:

Address a = new Address();
ChangeFieldInAddress(a);
// 即使已修改,a也将与以前相同
CreateANewInstance(ref a);
// 现在可能是一个全新的实例

out和ref关键字之间的主要区别在于,它ref要求变量由调用方初始化,同时out将责任传递给被调用方。

要使用out参数,方法定义和调用方法都必须显式使用out关键字。

int number = 1;
Console.WriteLine("在AddByRef之前: " + number); // 数= 1
AddOneByRef(ref number);
Console.WriteLine("在AddByRef之后: " + number);  // 数= 2
SetByOut(out number);
Console.WriteLine("在SetByOut之后: " + number);  // 数= 34

void AddOneByRef(ref int value)
{
    value++;
}

void SetByOut(out int value)
{
    value = 34;
}

以下就不能编译,因为out参数必须在方法返回之前分配(它会编译使用的值ref代替):

void PrintByOut(out int value)
{
    Console.WriteLine("Hello!");
}

使用out关键字作为通用修饰符

out定义通用接口和委托时,也可以在通用类型参数中使用关键字。在这种情况下,out关键字指定type参数是协变的。

通过协方差,您可以使用比通用参数指定的类型更多的派生类型。这允许实现变体接口的类的隐式转换和委托类型的隐式转换。引用类型支持协方差和协方差,但值类型不支持它们。-MSDN

//如果我们有这样的界面
interface ICovariant<out R> { }

//和两个变量
ICovariant<Object> iobj = new Sample<Object>();
ICovariant<String> istr = new Sample<String>();

// 那么以下语句是有效的
// 没有out关键字,这将引发错误
iobj = istr; // 隐式转换在这里发生