I understand (or at least I believe I do) what it means to pass an instance of a class to a method by ref versus not passing by ref. When or under what circumstances should one pass a class instance by ref? Is there a best practice when it comes to using the ref keyword for class instances?
The clearest explanation I've ever run across for output and ref parameters is ... Jon Skeet's.
Parameter Passing in C#
He doesn't go into "best practices", but if you understand the examples he's given, you'll know when you need to use them.
When you may replace the original object, you should send him as ref. If it's just for output and can be uninitialized before calling the function, you'll use out.
Put succinctly, you would pass a value as a ref parameter if you want the function you're calling to be able to alter the value of that variable.
This is not the same as passing a reference type as a parameter to a function. In those cases, you're still passing by value, but the value is a reference. In the case of passing by ref, then an actual reference to the variable is sent; essentially, you and the function you're calling "share" the same variable.
Consider the following:
public void Foo(ref int bar)
{
bar = 5;
}
...
int baz = 2;
Foo(ref baz);
In this case, the baz variable has a value of 5, since it was passed by reference. The semantics are entirely clear for value types, but not as clear for reference types.
public class MyClass
{
public int PropName { get; set; }
}
public void Foo(MyClass bar)
{
bar.PropName = 5;
}
...
MyClass baz = new MyClass();
baz.PropName = 2;
Foo(baz);
As expected, baz.PropName will be 5, since MyClass is a reference type. But let's do this:
public void Foo(MyClass bar)
{
bar = new MyClass();
bar.PropName = 5;
}
With the same calling code, baz.PropName will remain 2. This is because even though MyClass is a reference type, Foo has its own variable for bar; bar and baz just start out with the same value, but once Foo assigns a new value, they are just two different variables. If, however, we do this:
public void Foo(ref MyClass bar)
{
bar = new MyClass();
bar.PropName = 5;
}
...
MyClass baz = new MyClass();
baz.PropName = 2;
Foo(ref baz);
We'll end up with PropName being 5, since we passed baz by reference, making the two functions "share" the same variable.
The ref keyword allows you to pass an argument by reference. For reference types this means that the actual reference to an object is passed (rather than a copy of that reference). For value types this means that a reference to the variable holding the value of that type is passed.
This is used for methods that need to return more than one result but don't return a complex type to encapsulate those results. It allows you to pass a reference to a object into the method so that the method can modify that object.
The important thing to remember is that reference types are not normally passed by reference, a copy of a reference is passed. This means that you are not working with the actual reference that was passed to you. When you use ref on a class instance you are passing the actual reference itself so all modifications to it (like setting it to null for example) will be applied to the original reference.
When passing reference types (non-value-types) to a method, only the reference is passed in both cases. But when you use the ref keyword, the method being called can change the reference.
For example:
public void MyMethod(ref MyClass obj)
{
obj = new MyClass();
}
elsewhere:
MyClass x = y; // y is an instance of MyClass
// x points to y
MyMethod(ref x);
// x points to a new instance of MyClass
when calling MyMethod(ref x), x will point to the newly created object after the method call. x no longer points to the original object.
Most use cases for passing a reference variable by reference involve initialization and out is more appropriate than ref. And they compile to the same thing (the compiler enforces different constraints - that ref variables be initialized before being passed in and that out variables are initialized in the method). So the only case I can think of where this would be useful is where you need to do some checking of an instantiated ref variable and may need to reinitialize under certain circumstances.
This might also be necessary to modify an immutable class (like string) as pointed out by Asaf R.
I found that it is easy to run into trouble using the ref keyword.
The following method will modify f even without the ref keyword in the method signature because f is a reference type:
public void TrySet(Foo f,string s)
{
f.Bar = s;
}
In this second case however, the original Foo is affected only by the first line of code, the rest of the method somehow creates and affects only a new local variable.
public void TryNew(Foo f, string s)
{
f.Bar = ""; //original f is modified
f = new Foo(); //new f is created
f.Bar = s; //new f is modified, no effect on original f
}
It would be good if the compiler gave you a warning in that case. Basically what you are doing is replacing the reference you received with another one referencing a different memory area.
It you actually want to replace the object with a new instance, use the ref keyword:
public void TryNew(ref Foo f, string s)...
But are you not shooting yourself in the foot? If the caller is not aware that a new object is created, the following code will probably not work as intended:
Foo f = SomeClass.AFoo;
TryNew(ref f, "some string"); //this will clear SomeClass.AFoo.Bar and then create a new distinct object
And if you try to "fix" the problem by adding the line:
SomeClass.AFoo = f;
If the code holds a references to SomeClass.AFoo somewhere else, that reference will become invalid...
As a general rule, you probably should avoid using the new keyword to alter an object which you read from another class or received as a parameter in a method.
Regarding the use of the ref keyword with reference types, I can suggest this approach:
1) Don't use it if simply setting the values of the reference type but be explicit in your function or parameter names and in the comments:
public void SetFoo(Foo fooToSet, string s)
{
fooToSet.Bar = s;
}
2) When there is a legitimate reason to replace the input parameter with a new, different instance, use a function with a return value instead:
public Foo TryNew(string s)
{
Foo f = new Foo();
f.Bar = s;
return f;
}
But using this function may still have unwanted consequences with the SomeClass.AFoo scenario:
SomeClass.AFoo = TryNew("some string");//stores a different object in SomeClass.AFoo
3) In some cases such as the string swapping example here it is handy to use ref params, but just as in case 2 make sure that swapping the object addresses does not affect the rest of your code.
Because it manages memory allocation for you, C# makes it all too easy to forget everything about memory management but it really helps to understand how pointers and references work. Otherwise you may introduce subtle bugs that are difficult to find.
Finally, this is typically the case where one would want to use a memcpy like function but there is no such thing in C# that I know of.
Related
If the object being referenced as a parameter is being modified in a function, does it matter if you use ref or not? Is there a difference between the following two functions?
void DisposeObject(ClassThing c)
{
c.Dispose();
}
void DisposeObject(ref ClassThing c)
{
c.Dispose();
}
It doesn't matter. What matters is if you're assigning something to c (and want it reflected outside the method):
c = new ClassThing();
In that case you'd use ref.
It doesnt depend in your case.
BUT:
if you pass a reference object with the ref keyword you have inside of the method the possibility to change the reference to point to another Object of this type (so it will be visible outside of the method)
According to the MSDN guide to passing reference-type parameters:
When you pass a reference-type parameter by value, it is possible to change the data pointed to by the reference, such as the value of a class member. However, you cannot change the value of the reference itself; that is, you cannot use the same reference to allocate memory for a new class and have it persist outside the block. To do that, pass the parameter using the ref or out keyword.
So you can alter the original object, but you cannot change the original object to reference a different location in memory. Example:
static void Main()
{
int[] integerArray = new int[8];
foo(integerArray);
}
private void foo(int[] myArray)
{
myArray[0] = 5; //this changes integerArray
myArray = new int[4]; //this does not change integerArray,
// ... but it would if you used ref or out
}
So the difference does matter, although I don't know specifically about the behavior of Dispose().
I am reading Jeffrey Richters CLR via C#, and in it he says with ref parameters the reference itself is passed by value. This makes sense to me and seems analagous to pointers.
i.e. in C if I pass a pointer into a function and then assign the pointer via malloc it changes the pointer to point to the new memory location, however I know since the pointer itself is a copy it doesn't reassign the original pointer that was passed into the function. In order to accomplish change to the pointer outside the function I have to use a double pointer.
However, in C#:
void Swap(ref Object a, ref Object b)
{
Object t = b;
b = a;
a =t ;
}
works. This indicates to me that references aren't by value.
In analogy to the malloc above, I am assuming I could pass an object by reference and assign it a new object and the reassignment would persist outside the function.
Can someone clearup my confusion?
You have it slightly off. With reference types, the references are passed by value. Passing a ref parameter is different. In
private void Frob(Foo foo) // Foo is a class
{
}
A copy of the reference to the object of type Foo at the call site is passed into the method Frob. This copy of the reference is passed by value. This reference and the reference at the call site point to the same object in memory and will continue doing so until one of them is pointed at some other object in memory. For example, if inside this method, we write
foo = someOtherFoo;
Then the parameter is no longer referring to the same object as the object at the call site. The call site reference is unchanged.
Now consider if we introduce the ref keyword.
private void Frob(ref Foo foo)
{
foo = someOtherFoo;
}
In this situation, foo is an alias of the variable at the call site. These variables are not merely pointing at the same object in memory, it's as if they are the same variable! As a result, pointing foo to someOtherFoo is not only going to change foo inside this method, this change will also be reflected at the call site.
Without the ref keyword, an object's reference is passed by value.
With the ref keyword, a reference to an object's reference is passed by value.
[it's just that the compiler is hiding the fact that making the assignment to a parameter passed by explicit ref is changing the pointer]
When called this passes the original pointer value (the reference)
void Swap(ref Object a, ref Object b)
{
Object t = b;
b = a;
a = t;
}
This passes a copy of the original pointer:
void Swap(Object a, Object b)
{
Object t = b;
b = a;
a = t;
}
Both will point to the same object but changing the second won't be reflected in a greater scope that this method...
I do not exactly get the question though...
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
When to pass ref keyword in
Hi All,
I am just surprised that why we have ref in C# while by default everything which is a reference type in C# is passed as a reference.
In simpler words, can anyone explain me the difference between these two method calls:
public void Test(SomeClass someClass)
{
// some code here
}
and
public void Test(ref SomeClass someClass)
{
// some code here
}
In my thinking they both have reference to same memory location.
So why do we need ref keyword at all ?
The ref keyword passes in a reference to whatever location is storing the reference. This allows you to manipulate this variable from the called function. This is particularly useful for value types, but also has uses when used with reference types. (Dictionary.TryGetValue() being a good example. The out parameter is required to return the value stored in the dictionary. out is equivalent to ref except that it will undergo a different set of compile-time checks.)
For example:
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.
}
I am just surprised that why we have ref in C# while by default everything is which is a reference type in C# is passed as a reference.
Because some things in C# are value types, and sometimes we want to pass those. We have the ref keyword so that those things can be passed by reference also.
It's analogous to the difference between a SomeClass * and a SomeClass ** in C++.
With a SomeClass * (or without ref), we can modify the object pointed to, but we can't redirect it to an entirely new object.
With a SomeClass ** (or with ref), we can change the argument in the calling code in order to point it to an object of our choosing.
When you pass an object you pass it by reference. This means that anything you do to that object will be reflected in the object after the method returns. When you pass the reference by reference i.e. void Foo(ref object obj) you are passing the address of that object. You can then re-assign the address to a different object and that will be the state of things when the method returns
foo (object o)
{
...
}
var v = new object();
foo(v);
v will still reference the same object that was instantiated prior to the call to foo
void bar(ref object o)
{
o = null;
}
var v = new object();
foo(ref v);
// v is now null
Suppose method Foo accepts a Bar by value. If I have a Bar called "Boz", the statement:
Foo(Boz);
may take the object pointed to by Boz and change that object's characteristics, but it cannot change which object Boz points to. By contrast, if Boz were passed by reference, the same statement could cause Boz to point to a different object entirely.
As an example of usage, consider a routine that accepts an array as a parameter. If an array is passed by value, the recipient can change the value of any of the items in the array, but the recipient cannot change the size. The only way to change the size of an array is to create a new array, copy the old items into it, and from thence forth use the new array instead of the old one. When an array passed by value, there is no way for the recipient to tell the caller that it should stop using the old array and use the new one instead. With an array passed by reference that is not a problem.
I understand that if I pass a value-type (int, struct, etc.) as a parameter (without the ref keyword), a copy of that variable is passed to the method, but if I use the ref keyword a reference to that variable is passed, not a new one.
But with reference-types, like classes, even without the ref keyword, a reference is passed to the method, not a copy. So what is the use of the ref keyword with reference-types?
Take for example:
var x = new Foo();
What is the difference between the following?
void Bar(Foo y) {
y.Name = "2";
}
and
void Bar(ref Foo y) {
y.Name = "2";
}
You can change what foo points to using y:
Foo foo = new Foo("1");
void Bar(ref Foo y)
{
y = new Foo("2");
}
Bar(ref foo);
// foo.Name == "2"
There are cases where you want to modify the actual reference and not the object pointed to:
void Swap<T>(ref T x, ref T y) {
T t = x;
x = y;
y = t;
}
var test = new[] { "0", "1" };
Swap(ref test[0], ref test[1]);
Jon Skeet wrote a great article about parameter passing in C#. It details clearly the exact behaviour and usage of passing parameters by value, by reference (ref), and by output (out).
Here's an important quote from that page in relation to ref parameters:
Reference parameters don't pass the
values of the variables used in the
function member invocation - they use
the variables themselves. Rather than
creating a new storage location for
the variable in the function member
declaration, the same storage location
is used, so the value of the variable
in the function member and the value
of the reference parameter will always
be the same. Reference parameters need
the ref modifier as part of both the
declaration and the invocation - that
means it's always clear when you're
passing something by reference.
Very nicely explained here :
http://msdn.microsoft.com/en-us/library/s6938f28.aspx
Abstract from the article:
A variable of a reference type does not contain its data directly; it
contains a reference to its data. When you pass a reference-type
parameter by value, it is possible to change the data pointed to by
the reference, such as the value of a class member. However, you
cannot change the value of the reference itself; that is, you cannot
use the same reference to allocate memory for a new class and have it
persist outside the block. To do that, pass the parameter using the
ref or out keyword.
When you pass a reference type with the ref keyword, you pass the reference by reference, and the method you call can assign a new value to the parameter. That change will propagate to the calling scope. Without ref, the reference is passed by value, and this doesn't happen.
C# also has the 'out' keyword which is a lot like ref, except that with 'ref', arguments must be initialized before calling the method, and with 'out' you must assign a value in the receiving method.
It allows you to modify the reference passed in. e.g.
void Bar()
{
var y = new Foo();
Baz(ref y);
}
void Baz(ref Foo y)
{
y.Name = "2";
// Overwrite the reference
y = new Foo();
}
You can also use out if you don't care about the reference passed in:
void Bar()
{
var y = new Foo();
Baz(out y);
}
void Baz(out Foo y)
{
// Return a new reference
y = new Foo();
}
Another bunch of code
class O
{
public int prop = 0;
}
class Program
{
static void Main(string[] args)
{
O o1 = new O();
o1.prop = 1;
O o2 = new O();
o2.prop = 2;
o1modifier(o1);
o2modifier(ref o2);
Console.WriteLine("1 : " + o1.prop.ToString());
Console.WriteLine("2 : " + o2.prop.ToString());
Console.ReadLine();
}
static void o1modifier(O o)
{
o = new O();
o.prop = 3;
}
static void o2modifier(ref O o)
{
o = new O();
o.prop = 4;
}
}
In addition to the existing answers:
As you asked for the difference of the 2 methods: There is no co(ntra)variance when using ref or out:
class Foo { }
class FooBar : Foo { }
static void Bar(Foo foo) { }
static void Bar(ref Foo foo) { foo = new Foo(); }
void Main()
{
Foo foo = null;
Bar(foo); // OK
Bar(ref foo); // OK
FooBar fooBar = null;
Bar(fooBar); // OK (covariance)
Bar(ref fooBar); // compile time error
}
A parameter in a method seems to be always passing a copy, the question is a copy of what. A copy is done by a copy constructor for an object and since all variables are Object in C#, i believe this is the case for all of them. Variables(objects) are like people living at some addresses. We either change the people living at those addresses or we can create more references to the people living at those addresses in the phone book(make shallow copies). So, more than one identifier can refer to the same address. Reference types desire more space, so unlike value types that are directly connected by an arrow to their identifier in the stack, they have value for another address in the heap( a bigger space to dwell). This space needs to be taken from the heap.
Value type:
Indentifier(contains value =address of stack value)---->Value of value type
Reference type:
Identifier(contains value=address of stack value)---->(contains value=address of heap value)---->Heap value(most often contains addresses to other values), imagine more arrows sticking in different directions to Array[0], Array[1], array[2]
The only way to change a value is to follow the arrows. If one arrow gets lost/changed in the way the value is unreachable.
Reference Variables carry the address from one place to another so any updation on them at any place will reflect on all the places THEN what is the use of REF.
Reference variable (405) are good till no new memory is allocated to the reference variable passed in the method.
Once new memory allocate (410) then the value change on this object (408) will not reflect everywhere.
For this ref comes. Ref is reference of reference so whenever new memory allocate it get to know because it is pointing to that location therefore the value can be shared by everyOne. You can see the image for more clearity.
I want to give a certain linked list to a class I am making. I want the class to write into that list (eg by .addLast()).
Should I use the ref keyword for that?
I am somewhat puzzled on where to use the ref and out keywords in C#, as all classes are allocated dynamically on the heap and we actually use pointers for most operations.
Of course, out and ref keywords make sense for primitives and structs.
Also, if I don't send the list directly, but send a class containing the list? (it's internal and needed), do I still need to use ref? or if I pass it between functions, ex:
void A(ref LinkedList<int> list){
B(list);
}
void B(ref LinkedList<int> list){
_myList = list;
}
This is a common misconception of the use of ref keyword in C#. Its purpose is to pass either a value or a reference type by reference, and you only need it in specific circumstances where you need a direct reference to the actual argument, rather than a copy of the argument (be it a value or reference itself). It is imperative not to confuse reference types with passing by reference in any case.
Jon Skeet has written an excellent article about parameter passing in C#, which compares and contrasts value types, reference types, passing by value, passing by reference (ref), and output parameters (out). I recommend you take some time to read through this in full and your understanding should become much clearer.
To quote the most important parts from that page:
Value parameters:
By default, parameters are value
parameters. This means that a new
storage location is created for the
variable in the function member
declaration, and it starts off with
the value that you specify in the
function member invocation. If you
change that value, that doesn't alter
any variables involved in the
invocation
Reference parameters:
Reference parameters don't pass the
values of the variables used in the
function member invocation - they use
the variables themselves. Rather than
creating a new storage location for
the variable in the function member
declaration, the same storage location
is used, so the value of the variable
in the function member and the value
of the reference parameter will always
be the same. Reference parameters need
the ref modifier as part of both the
declaration and the invocation - that
means it's always clear when you're
passing something by reference. Let's
look at our previous examples, just
changing the parameter to be a
reference parameter:
To conclude: having read my reply and Jon Skeet's article, I hope that you will then see that there is no need whatsoever for using the ref keyword in the context of your question.
For what you're doing you don't need to use ref. If you did pass the list using ref, you would be allowing the caller to change which list you're referencing, rather than just changing the contents of the list.
The only time you need to use ref with a reference type is if you're going to be creating a new object inside a function.
Example #1: ref keyword not necessary.
// ...
List myList = new List();
PopulateList(myList);
// ...
void PopulateList(List AList)
{
AList.Add("Hello");
AList.Add("World");
}
Example #2: ref keyword necessary.
// ...
List myList;
PopulateList(ref myList);
// ...
void PopulateList(ref List AList)
{
AList = new List();
AList.Add("Hello");
AList.Add("World");
}
I know this is an old question, but none of the answers give a good direct reason why in my opinion.
You don't need to use ref in this instance, and here's why. Consider this function:
void Foo(MyClass a1, ref MyClass a2, out MyClass b1, int c1, MyStruct d1, ref MyStruct d2)
{
}
Now call this function as
MyClass a = new MyClass();
MyClass b = null
int c = 3;
MyStruct d = new MyStruct();
Foo(a, ref a, b, c, d, ref d);
Here's what you get inside of the function:
void Foo(MyClass a1, ref MyClass a2,
out MyClass b1,
int c1,
MyStruct d1, ref MyStruct d2)
{
a1 is a copy in memory of the pointer to the instantiated class a;
a2 is the pointer to the instantiated class a;
b1 is the pointer to b, but has the additional check of having to be set within this function - and cannot be used before being set;
c1 is a copy in memory of the variable c;
d1 is a copy in memory of the struct d;
d2 is the struct d;
}
Important things to realize:
setting a1 to null will not set a to null.
setting a2 to null will set a to null.
setting b1 is required.
setting c1 will not change c.
setting d1 will not change d.
setting d2 will change d.
This allows for some weirdness like this:
void Foo(MyClass x, ref MyClass y)
{
x = null;
y.Bar("hi");
}
Called like:
MyClass a = new MyClass();
Foo(a, ref a);
You are using a class, and so your situation is more like variable a1 in the function call. Which means ref isn't strictly required.
The Jon Skeet article won't help you that much because his example with IntHolder is a struct not a class. Struct is value type like int and must be handled the same way.
In the two snippets you posted there is no need to pass list by ref. To quote Jon Skeet, object references are passed by value. This means, you would want to ref a reference type when the method will or might change the object reference and you want this new reference to carry back to the calling method. For example:
void methodA(string test)
{
test = "Hello World";
}
void methodB(ref string test)
{
test = "Hello World";
}
void Runner()
{
string first= "string";
methodA(first);
string second= "string";
methodB(ref second);
Console.WriteLine((first == second).ToString()); //this would print false
}
I am adding this answer for programmers that are used to C++ like myself.
Classes, interfaces, delegatess and arrays are reference types, meaning that they have an underlying pointer. Normal function calls copy this pointer(reference) by value, while sending by reference sends sends a reference to this reference:
//C# code:
void Foo(ClassA input)
void Bar(ClassA ref input)
//equivalent C++ code:
void Foo(ClassA* input)
void Bar(ClassA*& input)
Primitives such as int, double, etc structs and strings(string are an exception to these, but works similar), are allocated on the heap, so things work a bit different:
//C# code:
void Foo(StructA input)
void Bar(StructA ref input)
//equivalent C++ code:
void Foo(StructA input)
void Bar(StructA& input)
the ref keyword needs to be used both in declaration of the method and when calling it, so it would be clear it is referenced:
//C# code:
void Foobar(ClassB ref input)
...
ClassB instance = new ClassB();
Foobar(ref instance);
//equivalent C++ code:
void Foobar(ClassB*& input)
...
ClassB instance* = new ClassB();
Foobar(instance);
As said before, please read this detailed explanation. It also explains about strings.
It is interesting to note that calling by reference works with an underlying pointer, so we get to this code:
//C# code:
void Foo(ClassA input){
input = input + 3;
}
void Bar(ClassA ref input){
input = input + 3;
}
//equivalent C++ code:
void Foo(ClassA& input){
input = input + 3;
}
void Bar(ClassA*& input){
*input = *input + 3;
}
//equivalent pure C code:
void Fun(ClassA* input){
*input = *input + 3;
}
void Fun(ClassA** input){
*(*input) = *(*input) + 3;
}
it's a rough equivalent, but it's somewhat true.
No you don't need to use ref.
LinkedList is an object, so it is already a reference type. The parameter list is a reference to the LinkedList object.
See this MSDN article for a description of value types. Value types are usually the parameters you would use the ref or out keywords with.
You may also want to pass reference types by ref. This will allow you to point the reference to another object.
Any time you pass an object o you are really passing a reference to the object. When you pass a `ref object o' you are passing a reference to the reference. This allows to you modify the reference.
Passing Reference-Type Parameters may also help you understand.