何时使用 ref 以及何时在 C# 中不需要
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/635915/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
When to use ref and when it is not necessary in C#
提问by Rex Logan
I have a object that is my in memory state of the program and also have some other worker functions that I pass the object to to modify the state. I have been passing it by ref to the worker functions. However I came across the following function.
我有一个对象,它是程序的内存状态,还有一些其他的工作函数,我将对象传递给它来修改状态。我一直通过 ref 将它传递给工作函数。但是我遇到了以下功能。
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);
It confuses me because both received_s
and remoteEP
are returning stuff from the function. Why does remoteEP
need a ref
and received_s
does not?
它混淆了我,因为两者received_s
并remoteEP
从函数返回的东西。为什么remoteEP
需要一个ref
和received_s
不?
I am also a c programmer so I am having a problem getting pointers out of my head.
我也是 ac 程序员,所以我在想办法解决问题时遇到了问题。
Edit: It looks like that objects in C# are pointers to the object under the hood. So when you pass an object to a function you can then modify the object contents through the pointer and the only thing passed to the function is the pointer to the object so the object itself is not being copied. You use ref or out if you want to be able to switch out or create a new object in the function which is like a double pointer.
编辑:看起来 C# 中的对象是指向引擎盖下对象的指针。因此,当您将对象传递给函数时,您可以通过指针修改对象内容,并且传递给函数的唯一内容是指向对象的指针,因此不会复制对象本身。如果您希望能够在函数中切换出或创建一个类似于双指针的新对象,则可以使用 ref 或 out。
采纳答案by Jon Skeet
Short answer: read my article on argument passing.
简短回答:阅读我关于参数传递的文章。
Long answer: when a reference type parameter is passed by value, only the reference is passed, nota copy of the object. This is like passing a pointer (by value) in C or C++. Changes to the value of the parameter itself won't be seen by the caller, but changes in the object which the reference points to willbe seen.
长答案:当按值传递引用类型参数时,只传递引用,而不是对象的副本。这就像在 C 或 C++ 中传递一个指针(按值)。调用者不会看到参数本身值的变化,但会看到引用指向的对象的变化。
When a parameter (of any kind) is passed byreference, that means that any changes to the parameter are seen by the caller - changes to the parameter arechanges to the variable.
当参数(任何种类的)被传递通过参考,这意味着,对参数的任何变化由呼叫者看到-更改参数是变化的变量。
The article explains all of this in more detail, of course :)
这篇文章当然更详细地解释了所有这些:)
Useful answer: you almost never need to use ref/out. It's basically a way of getting another return value, and should usually be avoided precisely because it means the method's probably trying to do too much. That's not always the case (TryParse
etc are the canonical examples of reasonable use of out
) but using ref/out should be a relative rarity.
有用的答案:您几乎不需要使用 ref/out。它基本上是一种获取另一个返回值的方法,通常应该避免使用它,因为这意味着该方法可能试图做太多事情。情况并非总是如此(TryParse
等是合理使用 的规范示例out
),但使用 ref/out 应该是相对罕见的。
回答by Chris Hynes
Since received_s is an array, you're passing a pointer to that array. The function manipulates that existing data in place, not changing the underlying location or pointer. The ref keyword signifies that you're passing the actual pointer to the location and updating that pointer in the outside function, so the value in the outside function will change.
由于 received_s 是一个数组,因此您传递了一个指向该数组的指针。该函数在适当的位置操作现有数据,而不更改底层位置或指针。ref 关键字表示您正在传递指向该位置的实际指针并在外部函数中更新该指针,因此外部函数中的值将发生变化。
E.g. the byte array is a pointer to the same memory before and after, the memory has just been updated.
例如,字节数组是指向同一内存之前和之后的指针,内存刚刚被更新。
The Endpoint reference is actually updating the pointer to the Endpoint in the outside function to a new instance generated inside the function.
Endpoint 引用实际上是将外部函数中指向 Endpoint 的指针更新为函数内部生成的新实例。
回答by Brian
Think of a ref as meaning you are passing a pointer by reference. Not using a ref means you are passing a pointer by value.
将 ref 视为您通过引用传递指针的意思。不使用 ref 意味着您正在按值传递指针。
Better yet, ignore what I just said (it's probably misleading, especially with value types) and read This MSDN page.
更好的是,忽略我刚才所说的(这可能会产生误导,尤其是对于值类型)并阅读这个 MSDN 页面。
回答by Michael Meadows
Think of a non-ref parameter as being a pointer, and a ref parameter as a double pointer. This helped me the most.
将非 ref 参数视为指针,将 ref 参数视为双指针。这对我帮助最大。
You should almost never pass values by ref. I suspect that if it wasn't for interop concerns, the .Net team would never have included it in the original specification. The OO way of dealing with most problem that ref parameters solve is to:
您几乎不应该通过 ref 传递值。我怀疑如果不是出于互操作的考虑,.Net 团队永远不会将它包含在原始规范中。处理 ref 参数解决的大多数问题的 OO 方法是:
For multiple return values
对于多个返回值
- Create structs that represent the multiple return values
- 创建表示多个返回值的结构
For primitives that change in a method as the result of the method call(method has side-effects on primitive parameters)
对于因方法调用而在方法中发生变化的基元(方法对基元参数有副作用)
- Implement the method in an object as an instance method and manipulate the object's state (not the parameters) as part of the method call
- Use the multiple return value solution and merge the return values to your state
- Create an object that contains state that can be manipulated by a method and pass that object as the parameter, and not the primitives themselves.
- 将对象中的方法作为实例方法实现,并将对象的状态(而不是参数)作为方法调用的一部分进行操作
- 使用多返回值解决方案并将返回值合并到您的状态
- 创建一个包含可由方法操作的状态的对象,并将该对象作为参数传递,而不是原语本身。
回答by Chris
You could probably write an entire C# app and never pass any objects/structs by ref.
您可能会编写一个完整的 C# 应用程序,并且永远不会通过 ref 传递任何对象/结构。
I had a professor who told me this:
我有一位教授告诉我:
The only place you'd use refs is where you either:
- Want to pass a large object (ie, the objects/struct has objects/structs inside it to multiple levels) and copying it would be expensive and
- You are calling a Framework, Windows API or other API that requires it.
Don't do it just because you can. You can get bit in the ass by some nasty bugs if you start changing the values in a param and aren't paying attention.
您唯一会使用 refs 的地方是您:
- 想要传递一个大对象(即,对象/结构内部有对象/结构到多个级别)并且复制它会很昂贵并且
- 您正在调用需要它的框架、Windows API 或其他 API。
不要仅仅因为你能做到。如果您开始更改参数中的值并且不注意,您可能会被一些讨厌的错误所困扰。
I agree with his advice, and in my five plus years since school, I've never had a need for it outside of calling the Framework or Windows API.
我同意他的建议,在我从学校毕业的五年多时间里,除了调用框架或 Windows API 之外,我从来没有需要它。
回答by Lucas
my understanding is that all objects derived from Object class are passed as pointers whereas ordinary types (int, struct) are not passed as pointers and require ref. I am nor sure about string (is it ultimately derived from Object class ?)
我的理解是,从 Object 类派生的所有对象都作为指针传递,而普通类型(int、struct)不作为指针传递并且需要 ref。我也不确定字符串(它最终是从 Object 类派生的吗?)
回答by Surender Singh Malik
Ground zero rule first, Primitives are passed by value(stack) and Non-Primitive by reference(Heap) in the context of TYPES involved.
首先是零规则,在涉及的类型的上下文中,基元通过值(堆栈)和非基元通过引用(堆)传递。
Parameters involved are passed by Value by default. Good post which explain things in details. http://yoda.arachsys.com/csharp/parameters.html
涉及的参数默认按Value传递。很好的帖子,详细解释了事情。 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
}
We can say(with warning) Non-primitive types are nothing but PointersAnd when we pass them by ref we can say we are passing Double Pointer
我们可以说(有警告)非原始类型不过是指针当我们通过 ref 传递它们时,我们可以说我们正在传递双指针
回答by Jon Davis
While I agree with Jon Skeet's answer overall and some of the other answers, there is a use case for using ref
, and that is for tightening up performance optimizations. It has been observed during performance profiling that setting the return value of a method has slight performance implications, whereas using ref
as an argument whereby the return value is populated into that parameter results in this slight bottleneck being removed.
虽然我同意 Jon Skeet 的总体答案和其他一些答案,但有一个 using 用例ref
,那就是加强性能优化。在性能分析期间已经观察到设置方法的返回值对性能有轻微影响,而ref
作为参数使用返回值填充到该参数中会导致这个轻微的瓶颈被消除。
This is really only useful where optimization efforts are taken to extreme levels, sacrificing readability and perhaps testability and maintainability for saving milliseconds or perhaps split-milliseconds.
这实际上仅在优化工作达到极端水平时才有用,牺牲可读性以及可能的可测试性和可维护性以节省毫秒或分割毫秒。