可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I\'m creating a function where I need to pass an object so that it can be modified by the function. What is the difference between:
public void myFunction(ref MyClass someClass)
and
public void myFunction(out MyClass someClass)
Which should I use and why?
回答1:
ref
tells the compiler that the object is initialized before entering the function, while out
tells the compiler that the object will be initialized inside the function.
So while ref
is two-ways, out
is out-only.
回答2:
The ref
modifier means that:
- The value is already set and
- The method can read and modify it.
The out
modifier means that:
- The Value isn\'t set and can\'t be read by the method until it is set.
- The method must set it before returning.
回答3:
Let\'s say Dom shows up at Peter\'s cubicle about the memo about the TPS reports.
If Dom were a ref argument, he would have a printed copy of the memo.
If Dom were an out argument, he\'d make Peter print a new copy of the memo for him to take with him.
回答4:
I am going to try my hand at an explanation:
I think we understand how the value types work right? Value types are (int, long, struct etc.). When you send them in to a function without a ref command it COPIES the data. Anything you do to that data in the function only affects the copy, not the original. The ref command sends the ACTUAL data and any changes will affect the data outside the function.
Ok on to the confusing part, reference types:
Lets create a reference type:
List<string> someobject = new List<string>()
When you new up someobject, two parts are created:
- The block of memory that holds data for someobject.
- A reference (pointer) to that block
of data.
Now when you send in someobject into a method without ref it COPIES the reference pointer, NOT the data. So you now have this:
(outside method) reference1 => someobject
(inside method) reference2 => someobject
Two references pointing to the same object. If you modify a property on someobject using reference2 it will affect the same data pointed to by reference1.
(inside method) reference2.Add(\"SomeString\");
(outside method) reference1[0] == \"SomeString\" //this is true
If you null out reference2 or point it to new data it will not affect reference1 nor the data reference1 points to.
(inside method) reference2 = new List<string>();
(outside method) reference1 != null; reference1[0] == \"SomeString\" //this is true
The references are now pointing like this:
reference2 => new List<string>()
reference1 => someobject
Now what happens when you send someobject by ref to a method?
The actual reference to someobject gets sent to the method. So you now have only one reference to the data:
(outside method) reference1 => someobject;
(inside method) reference1 => someobject;
But what does this mean? It acts exactly the same as sending someobject not by ref except for two main thing:
1) When you null out the reference inside the method it will null the one outside the method.
(inside method) reference1 = null;
(outside method) reference1 == null; //true
2) You can now point the reference to a completely different data location and the reference outside the function will now point to the new data location.
(inside method) reference1 = new List<string>();
(outside method) reference1.Count == 0; //this is true
回答5:
ref is in and out.
You should use out
in preference wherever it suffices for your requirements.
回答6:
out:
In C#, a method can return only one value. If you like to return more than one value, you can use the out keyword. The out modifier return as return-by-reference. The simplest answer is that the keyword “out” is used to get the value from the method.
- You don\'t need to initialize the value in the calling function.
- You must assign the value in the called function, otherwise the compiler will report an error.
ref:
In C#, when you pass a value type such as int, float, double etc. as an argument to the method parameter, it is passed by value. Therefore, if you modify the parameter value, it does not affect argument in the method call. But if you mark the parameter with “ref” keyword, it will reflect in the actual variable.
- You need to initialize the variable before you call the function.
- It’s not mandatory to assign any value to the ref parameter in the method. If you don’t change the value, what is the need to mark it as “ref”?
回答7:
Extending the Dog, Cat example. The second method with ref changes the object referenced by the caller. Hence \"Cat\" !!!
public static void Foo()
{
MyClass myObject = new MyClass();
myObject.Name = \"Dog\";
Bar(myObject);
Console.WriteLine(myObject.Name); // Writes \"Dog\".
Bar(ref myObject);
Console.WriteLine(myObject.Name); // Writes \"Cat\".
}
public static void Bar(MyClass someObject)
{
MyClass myTempObject = new MyClass();
myTempObject.Name = \"Cat\";
someObject = myTempObject;
}
public static void Bar(ref MyClass someObject)
{
MyClass myTempObject = new MyClass();
myTempObject.Name = \"Cat\";
someObject = myTempObject;
}
回答8:
Since you\'re passing in a reference type (a class) there is no need use ref
because per default only a reference to the actual object is passed and therefore you always change the object behind the reference.
Example:
public void Foo()
{
MyClass myObject = new MyClass();
myObject.Name = \"Dog\";
Bar(myObject);
Console.WriteLine(myObject.Name); // Writes \"Cat\".
}
public void Bar(MyClass someObject)
{
someObject.Name = \"Cat\";
}
As long you pass in a class you don\'t have to use ref
if you want to change the object inside your method.
回答9:
ref
and out
behave similarly except following differences.
ref
variable must be initialized before use. out
variable can be used without assignment
out
parameter must be treated as an unassigned value by the function that uses it. So, we can use initialized out
parameter in the calling code, but the value will be lost when the function executes.
回答10:
\"Baker\"
That\'s because the first one changes your string-reference to point to \"Baker\". Changing the reference is possible because you passed it via the ref keyword (=> a reference to a reference to a string).
The Second call gets a copy of the reference to the string.
string looks some kind of special at first. But string is just a reference class and if you define
string s = \"Able\";
then s is a reference to a string class that contains the text \"Able\"!
Another assignment to the same variable via
s = \"Baker\";
does not change the original string but just creates a new instance and let s point to that instance!
You can try it with the following little code example:
string s = \"Able\";
string s2 = s;
s = \"Baker\";
Console.WriteLine(s2);
What do you expect?
What you will get is still \"Able\" because you just set the reference in s to another instance while s2 points to the original instance.
EDIT:
string is also immutable which means there is simply no method or property that modifies an existing string instance (you can try to find one in the docs but you won\'t fins any :-) ). All string manipulation methods return a new string instance! (That\'s why you often get a better performance when using the StringBuilder class)
回答11:
For those that learn by example (like me) here\'s what Anthony Kolesov is saying.
I\'ve created some minimal examples of ref, out, and others to illustrate the point. I\'m not covering best practices, just examples to understand the differences.
https://gist.github.com/2upmedia/6d98a57b68d849ee7091
回答12:
Out:
A return statement can be used for returning only one value from a function. However, using output parameters, you can return two values from a function. Output parameters are like reference parameters, except that they transfer data out of the method rather than into it.
The following example illustrates this:
using System;
namespace CalculatorApplication
{
class NumberManipulator
{
public void getValue(out int x )
{
int temp = 5;
x = temp;
}
static void Main(string[] args)
{
NumberManipulator n = new NumberManipulator();
/* local variable definition */
int a = 100;
Console.WriteLine(\"Before method call, value of a : {0}\", a);
/* calling a function to get the value */
n.getValue(out a);
Console.WriteLine(\"After method call, value of a : {0}\", a);
Console.ReadLine();
}
}
}
ref:
A reference parameter is a reference to a memory location of a variable. When you pass parameters by reference, unlike value parameters, a new storage location is not created for these parameters. The reference parameters represent the same memory location as the actual parameters that are supplied to the method.
In C#, you declare the reference parameters using the ref keyword. The following example demonstrates this:
using System;
namespace CalculatorApplication
{
class NumberManipulator
{
public void swap(ref int x, ref int y)
{
int temp;
temp = x; /* save the value of x */
x = y; /* put y into x */
y = temp; /* put temp into y */
}
static void Main(string[] args)
{
NumberManipulator n = new NumberManipulator();
/* local variable definition */
int a = 100;
int b = 200;
Console.WriteLine(\"Before swap, value of a : {0}\", a);
Console.WriteLine(\"Before swap, value of b : {0}\", b);
/* calling a function to swap the values */
n.swap(ref a, ref b);
Console.WriteLine(\"After swap, value of a : {0}\", a);
Console.WriteLine(\"After swap, value of b : {0}\", b);
Console.ReadLine();
}
}
}
回答13:
ref and out work just like passing by references and passing by pointers as in C++.
For ref, the argument must declared and initialized.
For out, the argument must declared but may or may not be initialized
double nbr = 6; // if not initialized we get error
double dd = doit.square(ref nbr);
double Half_nbr ; // fine as passed by out, but inside the calling method you initialize it
doit.math_routines(nbr, out Half_nbr);
回答14:
ref means that the value in the ref parameter is already set, the method can read and modify it.
Using the ref keyword is the same as saying that the caller is responsible for initializing the value of the parameter.
out tells the compiler that the initialization of object is the responsibility of
the function, the function has to assign to the out parameter.
It\'s not allowed to leave it unassigned.
回答15:
Authoring Time:
(1) We create the calling method Main()
(2) it creates a List object (which is a reference type object) and stores it in the variable myList
.
public sealed class Program
{
public static Main()
{
List<int> myList = new List<int>();
During Runtime:
(3) Runtime allocates a memory on stack at #00, wide enough to store an address (#00 = myList
, since variable names are really just aliases for memory locations)
(4) Runtime creates a list object on heap at memory location #FF( all these addresses are for example sakes)
(5) Runtime would then store the starting address #FF of the object at #00(or in words, stores the reference of the List object in the pointer myList
)
Back to Authoring Time:
(6) We then pass the List object as argument myParamList
to the called method modifyMyList
and assign a new List object to it
List<int> myList = new List<int>();
List<int> newList = ModifyMyList(myList)
public List<int> ModifyMyList(List<int> myParamList){
myParamList = new List<int>();
return myParamList;
}
During Runtime:
(7) Runtime starts the call routine for the called method and as part of it, checks the type of parameters.
(8) Upon finding the reference type, it allocates a memory on stack at #04 for aliasing the parameter variable myParamList
.
(9) It then stores the value #FF in it as well.
(10) Runtime creates a list object on heap at memory location #004 and replaces #FF in #04 with this value(or dereferenced the original List object and pointed to the new List object in this method)
The address in #00 is not altered and retains the reference to #FF(or the original myList
pointer is not disturbed).
The ref keyword is a compiler directive to skip the generation of runtime code for (8) and (9) which means there will be no heap allocation for method parameters. It will use the original #00 pointer to operate on the object at #FF. If the original pointer is not initialised, the runtime will halt complaining it can’t proceed since the variable isn’t initialised
The out keyword is a compiler directive which pretty much is the same as ref with a slight modification at (9) and (10). The compiler expects the argument to be uninitialised and will continue with (8), (4) and (5) to create an object on heap and to stores its starting address in the argument variable. No uninitialised error will be thrown and any previous reference stored will be lost.
回答16:
They\'re pretty much the same - the only difference is that a variable you pass as an out parameter doesn\'t need to be initialised, and the method using the ref parameter has to set it to something.
int x; Foo(out x); // OK
int y; Foo(ref y); // Error
Ref parameters are for data that might be modified, out parameters are for data that\'s an additional output for the function (eg int.TryParse) that are already using the return value for something.
回答17:
public static void Main(string[] args)
{
//int a=10;
//change(ref a);
//Console.WriteLine(a);
// Console.Read();
int b;
change2(out b);
Console.WriteLine(b);
Console.Read();
}
// static void change(ref int a)
//{
// a = 20;
//}
static void change2(out int b)
{
b = 20;
}
you can check this code it will describe you its complete differnce
when you use \"ref\" its mean that u already initialize that int/string
but
when you use \"out\"
it works in both conditions wheather u initialize that int/string or not
but u must initialize that int/string in that function
回答18:
Ref:
The ref keyword is used to pass an argument as a reference. This means that when value of that parameter is changed in the method, it gets reflected in the calling method. An argument that is passed using a ref keyword must be initialized in the calling method before it is passed to the called method.
Out:
The out keyword is also used to pass an argument like ref keyword, but the argument can be passed without assigning any value to it. An argument that is passed using an out keyword must be initialized in the called method before it returns back to calling method.
public class Example
{
public static void Main()
{
int val1 = 0; //must be initialized
int val2; //optional
Example1(ref val1);
Console.WriteLine(val1);
Example2(out val2);
Console.WriteLine(val2);
}
static void Example1(ref int value)
{
value = 1;
}
static void Example2(out int value)
{
value = 2;
}
}
/* Output 1 2
Ref and out in method overloading
Both ref and out cannot be used in method overloading simultaneously. However, ref and out are treated differently at run-time but they are treated same at compile time (CLR doesn\'t differentiates between the two while it created IL for ref and out).
回答19:
Below I have shown an example using both Ref and out. Now, you all will be cleared about ref and out.
In below mentioned example when i comment //myRefObj = new myClass { Name = \"ref outside called!! \" };
line, will get an error saying \"Use of unassigned local variable \'myRefObj\'\", but there is no such error in out.
Where to use Ref: when we are calling a procedure with an in parameter and the same parameter will be used to store the output of that proc.
Where to use Out: when we are calling a procedure with no in parameter and teh same param will be used to return the value from that proc.
Also note the output
public partial class refAndOutUse : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
myClass myRefObj;
myRefObj = new myClass { Name = \"ref outside called!! <br/>\" };
myRefFunction(ref myRefObj);
Response.Write(myRefObj.Name); //ref inside function
myClass myOutObj;
myOutFunction(out myOutObj);
Response.Write(myOutObj.Name); //out inside function
}
void myRefFunction(ref myClass refObj)
{
refObj.Name = \"ref inside function <br/>\";
Response.Write(refObj.Name); //ref inside function
}
void myOutFunction(out myClass outObj)
{
outObj = new myClass { Name = \"out inside function <br/>\" };
Response.Write(outObj.Name); //out inside function
}
}
public class myClass
{
public string Name { get; set; }
}
回答20:
From the standpoint of a method which receives a parameter, the difference between ref
and out
is that C# requires that methods must write to every out
parameter before returning, and must not do anything with such a parameter, other than passing it as an out
parameter or writing to it, until it has been either passed as an out
parameter to another method or written directly. Note that some other languages do not impose such requirements; a virtual or interface method which is declared in C# with an out
parameter may be overridden in another language which does not impose any special restrictions on such parameters.
From the standpoint of the caller, C# will in many circumstances assume when calling a method with an out
parameter will cause the passed variable to be written without having been read first. This assumption may not be correct when calling methods written in other languages. For example:
struct MyStruct
{
...
myStruct(IDictionary<int, MyStruct> d)
{
d.TryGetValue(23, out this);
}
}
If myDictionary
identifies an IDictionary<TKey,TValue>
implementation written in a language other than C#, even though MyStruct s = new MyStruct(myDictionary);
looks like an assignment, it could potentially leave s
unmodified.
Note that constructors written in VB.NET, unlike those in C#, make no assumptions about whether called methods will modify any out
parameters, and clear out all fields unconditionally. The odd behavior alluded to above won\'t occur with code written entirely in VB or entirely in C#, but can occur when code written in C# calls a method written in VB.NET.
回答21:
If you want to pass your parameter as a ref then you should initialize it before passing parameter to the function else compiler itself will show the error.But in case of out parameter you don\'t need to initialize the object parameter before passing it to the method.You can initialize the object in the calling method itself.
回答22:
I was playing with the ref
and found this example quite interesting.
I thought the call of RefEater(ref s1);
will cause build error as in the second commented case, but the s1
field is initialized to its default value before the constructor is called (https://stackoverflow.com/a/1920659/5612780).
public class Class1
{
// this will have the default value
private string s1;
public Class1()
{
// no issue here..
RefEater(ref s1);
// Error CS0165 Use of unassigned local variable \'s2\'
//string s2;
//RefEater(ref s2);
}
private void RefEater(ref string s)
{
}
}
回答23:
I may not be so good at this, but surely strings (even though they are technically reference types and live on the heap) are passed by value, not reference?
string a = \"Hello\";
string b = \"goodbye\";
b = a; //attempt to make b point to a, won\'t work.
a = \"testing\";
Console.WriteLine(b); //this will produce \"hello\", NOT \"testing\"!!!!
This why you need ref if you want changes to exist outside of the scope of the function making them, you aren\'t passing a reference otherwise.
As far as I am aware you only need ref for structs/value types and string itself, as string is a reference type that pretends it is but is not a value type.
I could be completely wrong here though, I am new.
回答24:
Mind well that the reference parameter which is passed inside the function is directly worked on.
For example,
public class MyClass
{
public string Name { get; set; }
}
public void Foo()
{
MyClass myObject = new MyClass();
myObject.Name = \"Dog\";
Bar(myObject);
Console.WriteLine(myObject.Name); // Writes \"Dog\".
}
public void Bar(MyClass someObject)
{
MyClass myTempObject = new MyClass();
myTempObject.Name = \"Cat\";
someObject = myTempObject;
}
This will write Dog, not Cat. Hence you should directly work on someObject.