在c#中,当向方法发送参数时,我们应该何时使用"ref"和何时"out"以及什么时候不使用它们?

odi*_*seh 4 c# parameters methods

在c#中,当向方法发送参数时,我们应该何时使用"ref"和何时"out"以及什么时候不使用它们?

dri*_*iis 13

一般来说,如果可能的话,你应该避免使用ref和out.

话虽这么说,当方法可能需要修改值时使用ref .当方法总是应该为值赋值时使用out .

ref和out之间的区别在于,当使用时,编译器会强制执行规则,您需要在返回之前为out参数指定一些内容.使用ref时,必须在将变量用作ref参数之前为变量赋值.

显然,以上适用于您编写自己的方法时.如果需要调用在参数上使用ref或out修饰符声明的方法,则在调用方法时应在参数之前使用相同的修饰符.

还要记住,C#通过引用传递引用类型(类)(如,引用按值传递).因此,如果您提供一些引用类型作为参数的方法,该方法可以修改对象的数据; 即使没有引用或退出.但它不能修改引用本身(因为它不能修改引用的对象).


Col*_*kay 12

它们主要用于从方法调用中获取多个返回值.就个人而言,我倾向于不使用它们.如果我想要一个方法的多个返回值,那么我将创建一个小类来保存它们.

当您想要从该参数中的方法返回某些内容时,将使用ref和out.我记得,他们实际上都编译成了同样的IL,但C#实现了一些额外的东西,所以你必须具体.

这里有些例子:

static void Main(string[] args)
{
    string myString;
    MyMethod0(myString);
    Console.WriteLine(myString);

    Console.ReadLine();
}

public static void MyMethod0(string param1)
{
    param1 = "Hello";
}
Run Code Online (Sandbox Code Playgroud)

以上将无法编译,因为myString从未初始化.如果myString初始化为string.Empty,则程序的输出将为空行,因为所有MyMethod0都会将新字符串分配给对param1的本地引用.

static void Main(string[] args)
{
    string myString;
    MyMethod1(out myString);
    Console.WriteLine(myString);

    Console.ReadLine();
}


public static void MyMethod1(out string param1)
{
    param1 = "Hello";
}
Run Code Online (Sandbox Code Playgroud)

myString未在Main方法中初始化,但程序输出"Hello".这是因为Main方法中的myString引用正在从MyMethod1更新.MyMethod1不希望param1已经包含任何内容,因此它可以保持未初始化状态.但是,该方法应该分配一些东西.

static void Main(string[] args)
{
    string myString;
    MyMethod2(ref myString);
    Console.WriteLine(myString);

    Console.ReadLine();
}

public static void MyMethod2(ref string param1)
{
    param1 = "Hello";
}
Run Code Online (Sandbox Code Playgroud)

这再次不会编译.这是因为ref要求Main方法中的myString首先被初始化为某个东西.但是,如果更改Main方法以便将myString初始化为string.Empty,则代码将编译并且输出将为Hello.

因此,区别出来可以与未初始化的对象一起使用,ref必须传递初始化对象.如果您传递的对象没有任何引用,则无法替换它.

需要明确的是:如果传递的对象已经是引用类型,则该方法可以更新对象,并且更新将反映在调用代码中,但是无法更改对对象的引用.所以,如果我写这样的代码:

static void Main(string[] args)
{
    string myString = "Hello";
    MyMethod0(myString);
    Console.WriteLine(myString);

    Console.ReadLine();
}

public static void MyMethod0(string param1)
{
    param1 = "World";
}
Run Code Online (Sandbox Code Playgroud)

程序的输出将是Hello,而不是World,因为该方法仅更改了引用的本地副本,而不是传入的引用.

我希望这是有道理的.我的一般经验法则是不使用它们.我觉得这是回到OO之前的日子.(但那只是我的个人意见)


Mar*_*ell 6

(这是现有答案的补充 - 一些额外的考虑因素)

还有另一种使用refC#的方案,更常见于XNA之类的东西...通常,当你传递一个value-type(struct)时,它会被克隆.这使用堆栈空间和一些CPU周期,并且具有副作用,即struct对调用方法中的任何修改都将丢失.

(旁白:通常structs应该是不可变的,但XNA中的可变结构并不少见)

为了解决这个问题,ref在这些程序中看到很常见.

但是在大多数程序中(即使用classes作为默认值),通常可以通过"按值"传递引用(即没有ref/ out).


另一个非常常见的用例outTry*模式,例如:

string s = Console.ReadLine();
int i;
if(int.TryParse(s, out i)) {
    Console.WriteLine("You entered a valid int: " + i);
}
Run Code Online (Sandbox Code Playgroud)

或者类似地,TryGetValue在字典上.

这可以使用元组代替,但它是一种常见的模式,它可以被合理地理解,即使是那些挣扎太多ref/的人out.