【问题标题】:What is the difference when passing by ref in a method and without ref in C#? [duplicate]在方法中传递 ref 和在 C# 中不传递 ref 有什么区别? [复制]
【发布时间】:2010-12-21 20:56:10
【问题描述】:

可能重复:
When to pass ref keyword in

大家好,

我很惊讶为什么我们在 C# 中有 ref 而在默认情况下 C# 中的所有引用类型都作为引用传递。

用简单的话,谁能解释一下这两个方法调用之间的区别:

public void Test(SomeClass someClass)
{
  // some code here
} 

public void Test(ref SomeClass someClass)
{
  // some code here
}

在我看来,它们都引用了相同的内存位置。

那么为什么我们需要ref 关键字呢?

【问题讨论】:

    标签: c#


    【解决方案1】:

    ref 关键字将引用传递给存储引用的任何位置。这允许您从被调用的函数中操作此变量。这对于值类型特别有用,但在与引用类型一起使用时也有用。 (Dictionary.TryGetValue() 就是一个很好的例子。out 参数是返回存储在字典中的值所必需的。out 等价于 ref,只是它会经历一组不同的编译时检查。)

    例如:

    public void Test(ref SomeClass obj)
    {
        obj = null;
    }
    
    public void Test2(SomeClass obj)
    {
        obj = null;
    }
    
    public void Foo()
    {
        SomeClass obj = new SomeClass();
        Test(ref obj);
        // obj is null here!
    
        obj = new SomeClass();
        Test2(obj);
        // obj is not null here.
    }
    

    【讨论】:

    • 调用test2后,obj确实为null
    • @Cyber​​nate:不,不会。自己编译和测试。 Test2 中的obj = null 行只会将参数变量设置为null;它不会影响Foo 中的obj 本地。
    • 我的错...你是对的。今天学到了一个新东西:)。将我的投票添加到答案中......
    • @Cyber​​nate,调用 Test2 不会使 obj 无效。传递没有 ref 的 obj 会在堆中获得自己的堆栈,如果你不相信我试试看。编辑:没有刷新,所以我不知道您的评论已经得到答复。
    • @Gary:我尝试并意识到 obj = null 会将局部引用变量设置为指向 null 而不是原始内存分配
    【解决方案2】:

    我很惊讶为什么我们在 C# 中有 ref 而默认情况下,C# 中的所有引用类型都是作为引用传递的。

    因为 C# 中的某些东西是值类型,有时我们想要传递它们。我们有 ref 关键字,因此这些东西也可以通过引用传递。

    【讨论】:

      【解决方案3】:

      这类似于 C++ 中 SomeClass *SomeClass ** 之间的区别。

      使用SomeClass *(或不使用ref),我们可以修改指向的对象,但不能将其重定向到全新的对象。

      使用SomeClass **(或ref),我们可以更改调用代码中的参数以将其指向我们选择的对象。

      【讨论】:

      • 三重 *** 和更高的指针以及 ** 我希望 :)
      【解决方案4】:

      当你传递一个对象时,你通过引用传递它。这意味着您对该对象所做的任何事情都将在方法返回后反映在该对象中。当您通过引用传递引用时,即void Foo(ref object obj) 您正在传递该对象的地址。然后,您可以将地址重新分配给不同的对象,这将是方法返回时的状态

      foo (object o)
      {
         ...
      }
      
      var v = new object();
      foo(v);
      

      v 仍将引用在调用 foo 之前实例化的同一对象

      void bar(ref object o)
      {
         o = null;
      }
      
      var v = new object();
      foo(ref v);
      // v is now null
      

      【讨论】:

      • “当您通过引用传递引用时,即void Foo(ref object obj),您传递的是该对象的地址。” 不,您将引用的地址传递给该对象。传递对象的地址是没有ref 的情况。
      【解决方案5】:

      假设方法 Foo 按值接受 Bar。如果我有一个名为“Boz”的酒吧,则声明:

      富(博兹);

      可以获取 Boz 指向的对象并更改该对象的特征,但不能更改 Boz 指向的 对象。相比之下,如果 Boz 通过引用传递,相同的语句可能会导致 Boz 完全指向不同的对象。

      作为一个使用示例,考虑一个接受数组作为参数的例程。如果数组是按值传递的,接收者可以改变数组中任何一项的值,但接收者不能改变大小。更改数组大小的唯一方法是创建一个新数组,将旧项复制到其中,然后使用新数组而不是旧数组。当数组按值传递时,接收者无法告诉调用者它应该停止使用旧数组并改用新数组。通过引用传递的数组不是问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-12-23
        • 1970-01-01
        • 2016-03-24
        • 1970-01-01
        • 1970-01-01
        • 2012-04-25
        • 1970-01-01
        相关资源
        最近更新 更多