【问题标题】:C#, is there even a need to pass an object by reference? [duplicate]C#,甚至需要通过引用传递对象吗? [复制]
【发布时间】:2020-07-02 12:43:36
【问题描述】:

我正在尝试更新我对 C# 的理解。我以前使用过 Java,通过引用传递是我在 Java 中真正怀念的强大工具。但是,如果甚至需要通过引用传递对象以及是否存在可能有用的场景,我需要澄清一下? Stackoverflow 已经有多个关于引用的问题,它们确实很有启发性,但是,我想知道是否存在通过引用传递对象的场景。让我附上代码以更好地说明它。

class Program
    {
        public static void Update(int x) { x++; }
        public static void Update(ref int x) { x++; }
        public static void Update(Employee x) { x.msalary += 2000; }
        public static void Update(ref Employee x) { x.msalary += 2000; } //Do we even need this method? Is there a scenario where we might need this?

        static void Main(string[] args)
        {

            int a = 0;

            Update(a);
            Console.WriteLine("T1  " + a.ToString()); //a is still 0

            Update(ref a);
            Console.WriteLine("T2  " + a.ToString());//a is 1

            Employee emp2 = new Employee("Brent", "1234", "Blue", 1000); //salary is 1000

            Update(emp2.msalary);
            Console.WriteLine("T3  " + emp2.msalary.ToString());//salary does not change.

            Update(ref emp2.msalary);
            Console.WriteLine("T4  "+emp2.msalary.ToString());//salary changes to 1001

            Update(emp2);
            Console.WriteLine("T5  " + emp2.msalary.ToString()); //This changes, as expected for objects.

            Update(ref emp2);
            Console.WriteLine("T6  " + emp2.msalary.ToString()); //This also changes. But is there a scenario where we might need this?


        }
    }

【问题讨论】:

  • 您的Update(ref Employee x) 方法可以执行x = new Employee(),并且该更改反映在调用者中
  • 引用类型和值类型的场景是相同的 - 当您需要分配给被调用函数中的变量并使其在调用者中可见时。您没有在 ref Employee 示例中分配 x,因此它不是必需的。
  • 我会说只有当您想更改值并将其反映在范围之外时才使用值类型。仅当您可能使当前实例为空或需要为引用分配新实例时才适用于引用类型。
  • 在您的情况下,对 Employee 的引用没有被修改。您只是在修改实际对象,而不是对它的引用。
  • 您认为为什么 C# 中的有用场景与 Java 不同?

标签: c# pass-by-reference


【解决方案1】:

在我看来,称它为“ref”是错误的;考虑这个特性的正确方法是它使一个本地或参数成为另一个变量的别名。也就是说,当您使用ref 时,您只是为现有变量赋予了另一个名称

那么问题来了:在什么情况下修改别人的变量才有意义?这些是你应该使用ref的情况。

在历史上,ref 的主要用例类似于bool TryParse(string s, out int x),您希望有两个返回值:一个布尔值和一个整数。但是该方法是在泛型、可空对象和元组之前的 1 天在 C# 中创建的。现在更好的做法是:如果您需要返回一个可能无效的值类型,则返回一个可为空的,如果您需要返回两个值,则返回一个元组。 (请记住,out 只是 ref,需要先写后读。)

那么在使用元组和可为空值类型的新代码中,ref 的当前用例是什么?有一些算法可以通过直接读取和修改数据结构的另一部分中的变量来获得少量性能,但是您需要传递 which 变量需要读取和修改。即ref应该作为对某些数据类型的实现细节的性能优化。 (请记住,您不能永久存储 refs;您只能使 local 成为另一个变量的别名,并且 local 不能延长其生命周期!这极大地限制了用例供参考。)

您还可以使用ref 作为一种更简洁、类型安全的方式来与使用指针作为变量别名的非托管代码进行互操作。

就是这样。我几乎从不在主流的业务线代码中使用ref。它会在你需要的时候出现,但你几乎从不这样做。

【讨论】:

  • 感谢 Eric 的澄清。之前用C写过代码,ref让我想起了C中的指针功能。我认为使用ref可能会提高代码性能,但根据大家的反馈,我会避免使用它。
  • @baleeghr00:恕我直言,C 语言没有上面的“通过变量共享”功能,但 C++ 有。
  • 如果不是变量的别名,指针是什么?
  • 与 C/C++ 中类型指针的内存存储位置关联的变量包含对象的地址(在 C# 中也称为引用)。它与 C# 中的引用类型变量相同。别名共享相同的内存存储位置。
  • 当然,但我的意思是,如果我们有int x = 123;int *p = &x;,那么*p 也是一个变量,而且是x 的别名。我们不需要 C++ 引用;它们只是指针上的一种令人愉快的糖。
猜你喜欢
  • 2013-06-14
  • 2011-02-12
  • 1970-01-01
  • 2011-07-06
  • 2018-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-08
相关资源
最近更新 更多