Ref和Out有什么区别?

5
“可能重复问题”:
ref和out关键字有什么区别? refout 有什么区别?我对何时使用 refout 感到困惑。请解释如何使用 refout,以及在哪些情况下使用。

这是关于C#编程中ref和out关键字的区别的问题。 - Rune Grimstad
5个回答

14
  • 当您传递一个已初始化的参数并且希望方法/函数修改它时,使用 Ref
  • 当您传递未初始化的参数并且方法将需要初始化和填充该参数时(否则会出现警告甚至错误),请使用 Out

    bool IsUserValid(string username);

    void IsUserValid(string username, out bool valid);

以上声明基本相同。如果只需要返回一个值,则更容易使用返回类型。但是,如果您的方法还需要返回用户的生日,则无法在返回中同时返回两个参数,您必须使用 out 参数之一来返回其中一个(或将方法设置为 void 并作为 out 返回两个)。


完美的解释简洁易懂,谢谢。 - Marin

2
注意一点,就是何时(不)使用具有引用类型的参数的“ref”。 “ref”是用于引用本身,而不是引用所指向对象的内容。
如果您通过值传递引用(即没有'ref'或'out'),则无法更改引用(因此,“new”将无法在调用中生存),但是您仍然可以更改此引用所指向的属性的值(如果该类允许)。

1

通常不建议使用(或滥用)out和ref,通常更清晰的方法是返回一个包含多个需要“返回”的字段的结构体或简单类。

至于ref vs. out,out需要一个未初始化的变量,并且在退出函数之前设置out参数之前,代码将无法编译。

因此,下面的代码将不会编译:

bool TryParse(string text, out int result)
{
  if (text == null)
    return false;
  else
  {
     // do the parsing
  }
}

ref不需要您设置它们。正如Hans所提到的,当使用ref时,您实际上可以“new”引用类型的对象(因为您获得对引用的引用,这大致相当于C ++中的object **指针)


1

展示给你一个MSDN链接是更好的方式;)

从那个链接中:

refout之间的区别是微妙但重要的。每种参数传递模式都设计用于稍微不同的编程场景。out和ref参数之间的重要区别是它们各自使用的明确赋值规则。


0

实际上,有三种方法可以将参数传递给方法:按引用按值作为输出

按值是默认方式,在C#中没有关键字(在VB.Net中有:ByVal)- 它传递值类型的副本:

public void SomeMethod1(int num) 
{
    num = 2;
}

int myNum = 1;
SomeMethod1( myNum  );
// myNum is still 1, we just set a new one

令人困惑的是,按值传递引用类型时会传递引用的副本。这意味着您对引用类型所做的更改将指向实例,但您只有对引用指针的实际副本:

public void SomeMethod1(MyClass instance) 
{
    // changes the name on the instance
    instance.Name = "test 1";

    // we're only nulling the copy passed to this method
    instance = null;
}

public void SomeMethod2(MyClass instance) 
{
    // changes the name on the instance
    instance.Name = "test 2";

    // this is a new instance only in this method
    instance = new MyClass { Name = "new instance" };
}

MyClass myInst = new MyClass { Name = "original" };
SomeMethod1( myInst );
// myInst.Name is now "test 1"

SomeMethod2( myInst );
// myInst.Name is now "test 2"

好的,现在通过引用(C#中的ref或VB.Net中的ByRef)传递结构体的值的引用:

public void SomeMethod1(ref int num) 
{
    num = 2;
}

int myNum = 1;
SomeMethod1( ref myNum  );
// myNum is now 2, we changed the reference

这很简单,但对于引用类型,按引用传递实例的实际指针,而不是副本:

public void SomeMethod1(ref MyClass instance) 
{
    // changes the name on the instance
    instance.Name = "test 1";

    // we're nulling the reference passed to this method
    instance = null;
}

public void SomeMethod2(ref MyClass instance) 
{
    // changes the name on the instance
    instance.Name = "test 2";

    // this is a new instance replacing the original
    instance = new MyClass { Name = "new instance" };
}

MyClass myInst = new MyClass { Name = "original" };
SomeMethod1( ref myInst );
// myInst.Name will now throw a NullReferenceException because myInst is null

SomeMethod2( ref myInst );
// myInst.Name is now "new instance"

所以,虽然按引用传递按值传递对于引用类型来说是相似的,但如果你改变的是引用本身(而不是引用的内容),行为就非常不同。

最后作为输出是一个额外的返回变量,就像实际的返回值一样。这两者基本上是相同的:

public int SomeMethod1() 
{
    return 1;
}

public void SomeMethod2(out int num) 
{
    num = 1;
}

如果您有一个输出参数,它必须由方法填充(就像返回值一样)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接