关于C#:Ref 和Out的区别是什么?

What is diff Between Ref And Out?

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
Whats the difference between the 'ref' and 'out' keywords?

refout有什么区别?我对何时使用refout感到困惑。因此,请解释如何使用refout,以及在哪种情况下。


  • 当传递一个初始化的参数并且期望方法/函数对其进行修改时,可以使用ref。
  • 当传递未初始化的参数时使用out,方法必须初始化并填充该参数(否则将收到警告或错误)。

    bool isuservalid(字符串用户名);

    void isuservalid(字符串用户名,out bool有效);

上述声明大致相同。返回值比较容易,因此在本例中,您将使用返回类型。但是,如果您的方法还需要返回用户的出生日期,则不能在返回中同时返回这两个参数,则必须使用out参数返回其中一个参数(或者使方法无效,并将两者都返回为out)。


要注意的一件事是何时(不)对引用类型参数使用"ref"。"ref"用于引用本身,而不是引用指向的对象的内容。

如果传递一个"按值"引用(即,没有"ref"或"out"),则无法更改该引用(因此,"new"将无法在调用后继续存在),但仍然可以更改此引用指向的属性的值(如果类允许这样做)。


通常不希望使用(或滥用)out和ref,通常返回一个结构或简单类会更干净,其中包含需要"返回"的多个字段。

对于ref与out,out需要一个未初始化的变量,并且除非在退出函数之前设置out参数,否则代码不会编译。

因此,以下代码不会编译:

1
2
3
4
5
6
7
8
9
bool TryParse(string text, out int result)
{
  if (text == null)
    return false;
  else
  {
     // do the parsing
  }
}

裁判不要求你设置它们。正如汉斯提到的,在使用REF时,实际上可以"新建"引用类型的对象(因为您获得了引用的引用,它大致等于C++中的对象**指针)。


向您展示给您提供msdn链接的更好方法是什么;)

从这个链接:

The difference between ref and out is subtle but important. Each parameter passing mode is designed to apply to a slightly different programming scenario. The important difference between out and ref parameters is the definite assignment rules used by each.


实际上,向方法传递参数有三种方法:通过引用、通过值和作为输出。

"按值"是默认值,在C中没有关键字(在vb.net中是这样的:ByVal)—它传递值类型的副本:

1
2
3
4
5
6
7
8
public void SomeMethod1(int num)
{
    num = 2;
}

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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传递对结构值的引用:

1
2
3
4
5
6
7
8
public void SomeMethod1(ref int num)
{
    num = 2;
}

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

足够简单,但对于引用类型,通过引用将实际指针传递给实例,而不是副本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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"

因此,虽然对于引用类型而言,按引用和按值都是相似的,但是如果您要更改引用本身(而不是您所引用的内容),则行为是非常不同的。

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

1
2
3
4
5
6
7
8
9
public int SomeMethod1()
{
    return 1;
}

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

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