代码之家  ›  专栏  ›  技术社区  ›  Rex Logan

何时使用REF,当C中不需要时#

  •  94
  • Rex Logan  · 技术社区  · 16 年前

    我有一个对象,它是我程序的内存状态,也有一些其他的辅助函数,我通过它来修改状态。我一直把它通过引用传递给工作者函数。不过,我遇到了以下功能。

    byte[] received_s = new byte[2048];
    IPEndPoint tmpIpEndPoint = new IPEndPoint(IPAddress.Any, UdpPort_msg);
    EndPoint remoteEP = (tmpIpEndPoint);
    
    int sz = soUdp_msg.ReceiveFrom(received_s, ref remoteEP); 
    

    它让我困惑,因为两者都是 received_s remoteEP 正在从函数返回内容。为什么 遥控器 需要一个 ref 应收帐款 不是吗?

    我也是一个C程序员,所以我在把指针从我的头脑中拿出来时遇到了一个问题。

    编辑: 看起来C中的对象是指向引擎盖下对象的指针。因此,当您将一个对象传递给一个函数时,您可以通过指针修改对象内容,传递给该函数的唯一东西就是指向该对象的指针,这样对象本身就不会被复制。如果要在函数中像双指针一样切换或创建新对象,可以使用ref或out。

    8 回复  |  直到 7 年前
        1
  •  188
  •   Jon Skeet    16 年前

    简短回答:阅读我的 article on argument passing .

    长答:引用类型参数按值传递时,只传递引用。 对象的副本。这就像在C或C++中传递一个指针(按值)。调用者不会看到对参数本身值的更改,但会看到引用指向的对象中的更改。 被看见。

    传递参数(任何类型)时 通过 引用,这意味着调用方可以看到对参数的任何更改-对参数的更改 变量的更改。

    当然,这篇文章更详细地解释了这一切:)

    有用答案: 你几乎不需要使用REF/OUT .这基本上是获取另一个返回值的一种方法,通常应该避免使用,因为这意味着该方法可能做得太多了。情况并非总是如此( TryParse ETC是合理使用 out )但是使用ref/out应该是相对罕见的。

        2
  •  26
  •   Michael Meadows    16 年前

    把非引用参数看作指针,把引用参数看作双指针。这对我帮助最大。

    您几乎不应该按引用传递值。我怀疑如果不是出于互操作方面的考虑,.NET团队将永远不会在原始规范中包含它。处理参考参数所解决的大多数问题的OO方法是:

    对于多个返回值

    • 创建表示多个返回值的结构

    对于因方法调用而在方法中更改的基元 (方法对原始参数有副作用)

    • 将对象中的方法实现为实例方法,并作为方法调用的一部分操作对象的状态(而不是参数)
    • 使用多返回值解决方案并将返回值合并到您的状态
    • 创建一个对象,该对象包含可由方法操作的状态,并将该对象作为参数传递,而不是基元本身。
        3
  •  9
  •   sdgfsdh    9 年前

    您可能会编写一个完整的C应用程序,并且永远不会按引用传递任何对象/结构。

    我有个教授告诉我:

    您使用refs的唯一地方是:

    1. 想要传递一个大对象(即,对象/结构 它内部的对象/结构到多个级别)并将其复制到 很贵,而且
    2. 您正在调用需要的框架、Windows API或其他API 它。

    不要因为你能做到就这么做。你可以被一些人咬屁股 如果您开始更改参数中的值而不是 注意。

    我同意他的建议,在我上学五年多的时间里,除了调用框架或WindowsAPI之外,我从来没有需要过它。

        4
  •  3
  •   Chris Hynes    16 年前

    因为接收到的是一个数组,所以您将向该数组传递一个指针。函数操作现有数据,而不更改基础位置或指针。ref关键字表示您正在将实际指针传递到位置,并在外部函数中更新该指针,因此外部函数中的值将更改。

    例如,字节数组是指向同一内存的指针,在此之前和之后,内存刚刚更新。

    端点引用实际上正在将指向外部函数中端点的指针更新为在函数内部生成的新实例。

        5
  •  3
  •   Brian    16 年前

    把ref想象成一个引用传递一个指针。不使用ref意味着您正在按值传递指针。

    更好的是,忽略我刚才所说的(这可能会产生误导,尤其是对于值类型)并阅读 This MSDN page .

        6
  •  0
  •   Lucas    13 年前

    我的理解是,从对象类派生的所有对象都作为指针传递,而普通类型(int,struct)不作为指针传递,需要引用。我对字符串(它最终是从对象类派生的吗?)

        7
  •  0
  •   Jon Davis Glenn Block    7 年前

    虽然我完全同意乔恩·斯基特的答案和其他一些答案,但有一个用例可以使用 ref ,这是为了加强性能优化。在性能分析过程中观察到,设置方法的返回值对性能影响很小,而使用 裁判 作为一个参数,返回值被填充到该参数中会导致这个轻微的瓶颈被消除。

    只有在优化工作达到极端水平时,这才真正有用,因为这样做会牺牲可读性,可能会牺牲可测试性和可维护性,从而节省毫秒或拆分毫秒。

        8
  •  -1
  •   Community CDub    8 年前

    基本零规则首先,在涉及类型的上下文中,原语按值(堆栈)和非原语按引用(堆)传递。

    默认情况下,所涉及的参数按值传递。 很好的文章能详细解释问题。 http://yoda.arachsys.com/csharp/parameters.html

    Student myStudent = new Student {Name="A",RollNo=1};
    
    ChangeName(myStudent);
    
    static void ChangeName(Student s1)
    {
      s1.Name = "Z"; // myStudent.Name will also change from A to Z
                    // {AS s1 and myStudent both refers to same Heap(Memory)
                    //Student being the non-Primitive type
    }
    
    ChangeNameVersion2(ref myStudent);
    static void ChangeNameVersion2(ref Student s1)
    {
      s1.Name = "Z"; // Not any difference {same as **ChangeName**}
    }
    
    static void ChangeNameVersion3(ref Student s1)
    {
        s1 = new Student{Name="Champ"};
    
        // reference(myStudent) will also point toward this new Object having new memory
        // previous mystudent memory will be released as it is not pointed by any object
    }
    

    我们可以说(带有警告)非原始类型只是 指针 当我们通过裁判时,我们可以说我们已经通过了 双指针

    推荐文章