【问题标题】:Use of 'ref' keyword in C# [duplicate]在 C# 中使用“ref”关键字 [重复]
【发布时间】:2011-06-16 07:17:07
【问题描述】:

可能的重复:
Why use ref keyword when passing an Object?
When to pass ref keyword in

C# 中“ref”关键字的正确用法是什么。我相信已经有很多关于此的讨论线程,但我不清楚的是:

  1. 如果要传入引用对象,是否需要 ref 关键字?我的意思是当你在堆中创建一个对象时,它并不总是通过引用传递。这是否必须明确标记为参考?

【问题讨论】:

标签: c# .net


【解决方案1】:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace InOutRef
{
    static class InOutRef
    {
        public static void In(int i)
        {
            Console.WriteLine(i);
            i=100;
            Console.WriteLine(i);
        }
        public static void Ref(ref int i)
        {
            Console.WriteLine(i);
            i=200;
            Console.WriteLine(i);
        }
        public static void Out(out int i)
        {
            //Console.WriteLine(i); //Error Unsigned Ref
            i=300;
            Console.WriteLine(i);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            int i = 1;
            InOutRef.In(i); //passed by value (in only)
            Debug.Assert(i==1);
            InOutRef.Ref(ref i); //passed by ref (in or out)
            Debug.Assert(i == 200);
            InOutRef.Out(out i); //passed by as out ref (out only)
            Debug.Assert(i == 300);
        }
    }
}

我的回答不能再直白了。当使用 in 时,代码将不会记住引用更改,例如经典的 Java 交换 question。但是,当使用 ref 时,它将类似于 VB.NET,因为它会记住 inout 的变化。如果您使用 out 参数,则意味着必须在返回之前声明它(这是由编译器强制执行的)。

输出: 1 //1 来自主 100 //100 来自 in 1 //1 不会从 In 中记住 200 //200 来自参考 //此处应为 200,但 out 强制输出参数(未打印,因为已注释掉) 300 //300 只出 按任意键继续 。 . .

【讨论】:

    【解决方案2】:

    这里的答案中有很多令人困惑的错误信息。理解这一点的最简单方法是放弃“ref”意味着“通过引用”的想法。更好的思考方式是“ref”的意思是“我希望被调用方的这个形式参数成为调用方特定变量的别名”。

    当你说

    void M(ref int y) { y = 123; }
    ...
    int x = 456;
    M(ref x);
    

    也就是说“在调用 M 期间,被调用方的形参 y 是调用方变量 x 的另一个名称”。将 123 分配给 y 与将 123 分配给 x 完全相同,因为它们是同一个变量,一个有两个名称的变量。

    就是这样。不要考虑引用类型或值类型或其他任何东西,不要考虑按引用传递或按值传递。所有“ref”的意思是“暂时为这个变量命名”。

    【讨论】:

      【解决方案3】:

      使用ref 表示将引用 传递给函数。

      默认行为是函数接收对同一对象的新引用。这意味着如果您更改引用的值(例如,将其设置为新对象),那么您将不再指向原始的源对象。当您使用 ref 传递时,更改引用的值会更改源引用 - 因为它们是相同的。

      考虑一下:

      public class Thing
      {
          public string Property {get;set;}
      }
      
      public static void Go(Thing thing)
      {
          thing = new Thing();
          thing.Property = "Changed";
      }
      
      public static void Go(ref Thing thing)
      {
          thing = new Thing();
          thing.Property = "Changed";
      }
      

      然后如果你运行

      var g = new Thing();
      
      // this will not alter g
      Go(g);
      
      // this *will* alter g
      Go(ref g);
      

      【讨论】:

      • +1 最后,一个正确的答案。把这样的问题留得太久是很危险的,因为那里有太多的错误信息。很高兴在这里使用除反对票以外的其他东西。
      • 害怕有人反对这个;我不想和那个人一起工作!
      • 可能有人对这里给出的答案的大量反对票感到不安。这是我没有尝试提供自己的主要原因。更糟糕的是想象与仍然在 cmets 中尝试和争论的人一起工作。
      【解决方案4】:

      我相信 ref 关键字表明您通过引用而不是值传递对象。例如:

      void myfunction(ref object a) {
      a = new Something();
      }
      

      会改变调用函数中a的值 不过,

      void myfunction(object a) {
      a = new Something();
      }
      

      将在本地更改 a 的值,但不会在调用函数中更改。您仍然可以更改项目的属性,但不能设置项目本身的值。例如; a.someproperty = value;

      在这两种情况下都可以使用。

      【讨论】:

      • 第二个例子(没有 ref)将无法编译,因为这就像说 1 = 3。1 不可能等于 3。但是,使用 ref。好像在说。 x = 1。然后 x = 3。
      • 第二个例子会“工作”,但可能会产生意想不到的结果!
      • 我猜它编译,但它不会改变调用函数上下文中 a 的值。
      • 在对a 的引用在本地成功重新分配的意义上是可行的。但这种变化不会反映回调用函数。它肯定不会导致编译时错误。
      猜你喜欢
      • 2014-11-15
      • 2010-12-31
      • 2023-03-28
      • 2010-12-18
      • 2011-10-10
      • 2021-07-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多