Reputation: 7929
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;
}
Upvotes: 22
Views: 34288
Reputation: 147260
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.
Upvotes: 33
Reputation: 317
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:
a1
to null
will not set a
to null
.a2
to null
will set a
to null
.b1
is required.c1
will not change c
.d1
will not change d
.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.
Upvotes: 3
Reputation: 6950
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.
Upvotes: 1
Reputation: 35107
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");
}
Upvotes: 19
Reputation: 7929
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.
Upvotes: 2
Reputation: 15785
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
}
Upvotes: 2
Reputation:
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.
Upvotes: 23