【问题标题】:In c# , when sending a parameter to a method, when should we use "ref" and when "out" and when without any of them?在 c# 中,当向方法发送参数时,我们应该什么时候使用“ref”,什么时候使用“out”,什么时候不使用它们?
【发布时间】:2010-11-10 02:06:34
【问题描述】:

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

【问题讨论】:

    标签: c# methods parameters


    【解决方案1】:

    真的很简单。您使用与方法中最初声明参数的关键字完全相同的关键字。如果它被声明为out,则必须使用out。如果它被声明为ref,则必须使用ref

    【讨论】:

    • 我认为 odiseh 的意思是在编写自己的方法时,但我可能错了!
    【解决方案2】:

    一般来说,如果可能,您应该避免使用 ref 和 out。

    话虽如此,当方法可能需要修改值时使用ref。当方法总是应该为值赋值时使用 out。

    ref 和 out 的区别在于,在使用 out 时,编译器会强制执行规则,即您需要在返回之前为 out 参数赋值。使用 ref 时,必须在将变量用作 ref 参数之前为变量赋值。

    显然,当您编写自己的方法时,上述内容适用。如果您需要调用在其参数上使用 ref 或 out 修饰符声明的方法,则在调用方法时应在参数前使用相同的修饰符。

    还请记住,C# 通过引用传递引用类型(类)(如引用按值传递)。所以如果给某个方法提供引用类型作为参数,该方法可以修改对象的数据;即使没有 ref 或 out。但它不能修改引用本身(例如,它不能修改被引用的对象)。

    【讨论】:

      【解决方案3】:

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

      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";
      }
      

      上面的代码不会编译,因为 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";
      }
      

      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";
      }
      

      这同样不会编译。这是因为 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";
      }
      

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

      我希望这是有道理的。我的一般经验法则就是不要使用它们。我觉得这是回到 OO 之前的日子。 (不过,这只是我的看法)

      【讨论】:

      • Colin,非常感谢....但是假设我们不使用“param1”作为字符串(我们都知道字符串是引用类型),而是将 DataTable 传递给您的最后一个方法...令人惊讶的是,我们的 DataTable 中可能有一些行(当然,如果方法想要填充它)并且我们返回程序的主体,我们可以对 DataTable 行做一些事情。你的想法?
      • 此外,您能否先举个例子:“就我个人而言,我倾向于不使用它们。如果我想要一个方法的多个返回值,那么我将创建一个小类来抓住他们。”
      【解决方案4】:

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

      在 C# 中使用 ref 还有另一种情况,在 XNA 等中更常见...通常,当您传递值类型 (struct) 时,它会被克隆。这会使用堆栈空间和一些 CPU 周期,并具有副作用,即在调用的方法中对 struct 的任何修改都会丢失。

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

      为了解决这个问题,在此类程序中看到ref 是很常见的。

      但在大多数程序中(即默认使用classes),通常只需“按值”传递引用(即不ref/out)。


      out 的另一个非常常见用例是Try* 模式,例如:

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

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

      这可以使用元组代替,但它是一种常见的模式,即使是那些与ref/out 斗争太多的人也可以合理理解。

      【讨论】:

        【解决方案5】:

        尽量避免使用 ref. Out 没关系,因为你知道会发生什么,即使函数失败,旧值也会消失,新值会出现在你的变量中。但是,仅通过查看函数,您不知道 ref 参数会发生什么。它可能是相同的、修改的或全新的对象。

        每当我看到 ref 时,我都会紧张。

        【讨论】:

          【解决方案6】:

          ref 是要避免的(我相信这也有一个 fx-cop 规则)但是当引用的对象本身可能发生变化时使用 ref 。如果您看到 'ref' 关键字,您就知道在调用方法后,底层对象可能不再被同一个变量引用。

          【讨论】:

            【解决方案7】:

            除了 Colin 的详细回答,您还可以使用 out 参数从一个方法调用中返回多个值。参见下面的方法,它返回 3 个值。

            static void AssignSomeValues(out int first, out bool second, out string third)
                {
                    first = 12 + 12;
                    second = false;
                    third = "Output parameters are okay";
                }
            

            你可以这样使用它

            static void Main(string[] args) {
                    int i;
                    string s;
                    bool b;
            
                    AssignSomeValues(out i, out b, out s);
            
                    Console.WriteLine("Int value: {0}", i);
                    Console.WriteLine("Bool value: {0}", b);
                    Console.WriteLine("String value: {0}", s);
            
                    //wait for enter key to terminate program
                    Console.ReadLine(); }
            

            只需确保为每个输出参数分配一个有效值即可避免出错。

            【讨论】:

              猜你喜欢
              • 2021-09-07
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2010-11-13
              • 1970-01-01
              • 2010-12-30
              相关资源
              最近更新 更多