What does ref exactly do in C#?

VinylxScratches

Golden Member
Feb 2, 2009
1,666
0
0
using System;

public class ClassData
{
public static string sr(string str)
{
string newString = "Dee " + str;
return newString;
}

public static void sr2(ref string str)
{
str = "Dee";
}

public ClassData()
{

}
}

public class App
{
public static void Main(string[] args)
{
string str = ClassData.sr("Hello");
Console.WriteLine(str); // Produces "DeeHello" as output

string hello = "Hello";
ClassData.sr2(ref hello);
Console.WriteLine(hello); // Produces "Dee" as output

System.Threading.Thread.Sleep(2000);
}
}

What does it do in this situation? I can't wrap my head around this stuff sometimes :(

From the Microsoft site it says "Ref and out parameter passing modes are used to allow a method to alter variables passed in by the caller."

 

tatteredpotato

Diamond Member
Jul 23, 2006
3,934
0
76
Keep in mind that everything you declare in C# is a reference to an object internally. Every parameter(except ValueType iirc) that gets passed is passed by reference, meaning any changes you make to the object will show up on the original source (just like passing by reference in C++). Now in C# when you add ref, you are passing the reference by reference, meaning you can change what it points to.

Try this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<int> data = new List<int>();
Foo(data);
Console.WriteLine("Printing In Main");
foreach (int i in data)
Console.WriteLine(i);

Console.ReadLine();
}

static void Foo(List<int> data)
{
data.Add(5);
Console.WriteLine("Printing in Foo");
foreach (int i in data)
Console.WriteLine(i);
}
}
}

You'll notice the changes made to the data list get reflected in the main function.

Now modify Foo() to be:

static void Foo(List<int> data)
{
data = new List<int>();
data.Add(5);
Console.WriteLine("Printing in Foo");
foreach (int i in data)
Console.WriteLine(i);
}

It no longer reflects the changes made in Foo() in the main() function. This is because you changed the object you passed to.

Finally change:

Foo(List<int> data) to Foo(ref List<int> data), and change Foo(data) to Foo(ref data)

You should now see the changes show up. Ref lets you change what object your variable is "pointing" to. Hopefully someone might be able to explain this a little better than me (my C# is a little rusty too).
 

presidentender

Golden Member
Jan 23, 2008
1,166
0
76
OC's right, but let me give it a shot anyway. The 'ref' keyword allows you to pass a reference to a variable as an argument, instead of a copy of that variable. That is, your function will operate using the "real" variable at its original location in memory, rather than a copy of the variable. This means that you can change the value of the variable within your function:

class Program
{
static void Main(string[] args)
{
int i = 10;
int j = 5;
int k = Foo(ref i, ref j);

Console.WriteLine("i = " + i + ", j = " + j + ", k = " + k);
Console.Read();
}

static int Foo(ref int i, ref int j)
{
int k = i + j;
i = 999999999;
j = 37;
return k;
}
}

After executing "Foo," the values of i and j are changed. Without reference variables, we can change the values of the integers called i and j within the function, but these changes are lost after the return statement, since we're operating on a different object in memory.

Essentially, you use ref when you want to change the values of more than one variable with a function.

(Why is this so difficult to explain?)
 

tatteredpotato

Diamond Member
Jul 23, 2006
3,934
0
76
Originally posted by: presidentender

(Why is this so difficult to explain?)

If you know C++ it would probably be closest to pointers to pointers, which admittedly aren't easy to explain themselves.

Also keep in mind that presidentender's example is slightly different than mine as ints are Value Types while a List<> is a Reference Type. If you don't know the difference I'd suggest you look it up, as it's very useful to know.
 

Rangoric

Senior member
Apr 5, 2006
530
0
71
Anything related to pointers gets a bit complex.

(Another explanation)

--Prelude
There are 2 TYPES of objects.

You have Value types where the variable IS the object.
Then you have Reference types which only POINT at the object.

When you pass in a variable to a method, its value gets copied to the method.

For Values types, that means the OBJECT itself gets copied.
For Reference types, that means the thing that POINTS at the object gets copied.

a string is a Value Type, that IS a string, and when given to a method the OBJECT gets copied.

--Onto your example
So for:
public static void sr2(ref string str)
{
str = "Dee";
}

string hello = "Hello";
ClassData.sr2(ref hello);

In this example of yours we have a Value Type variable of hello, it has a value of "Hello".

What ref does is lets the method know that we want to know what happens to that variable. So instead of copying the object into the method, it gives the actual object to the method.

So that "ref string str" actually means "take what they give me and give it an alias of str". Whenever you have str in that method, it really means the variable 'hello' that you gave to it.

--To sum up
ref means "Here change this for me."
out means "Do you have an X for me?"
neither means "What can you do with this value?"

--Note
Reference Types (say you made a car class and have a variable of one like "Car vCar = new Car();") act differently and CAN be changed without a 'ref' in the method parameter. This is because you are only dealing with something that POINTS at the car, not the car itself. You would use ref if you wanted to change WHICH car it pointed at.
 

Markbnj

Elite Member <br>Moderator Emeritus
Moderator
Sep 16, 2005
15,682
14
81
www.markbetz.net
The difference between reference and value types can seem very subtle, and despite the abstract nature of memory management in .NET I think people who have a background in C or C++ have an easier time understanding this. I'll take a stab at it, since I'm waiting for a batch to run :).

[00000000] <-- memory location

Here we have a location in the computer's memory. You can see that it is 4 bytes wide, so it is a dword and able to store values between -2 billion and something and +2 billion and something.

Locations in memory aren't very memorable, so let's create another one, but give it a name:

long l;
[00000000] <-- l refers to this memory location

l = 1;
[00000100] <-- l = 1 (on little endian platforms like Intel)

l = 2;
[00000200] <-- l = 2 (the 1 is overwritten)

Now, since a memory location can hold a number, and the address of a location in memory _is_ a number, it follows that a memory location can hold the address of another memory location. Voila, le pointer is born. But since this is C#, let's not call the location that holds the address a pointer. Instead let's call it a reference.

MyObject o = new MyObject();

This statement can be broken down as follows:

1. Allocate the variable o, of type MyObject, on the runtime stack.
2. Allocate enough memory for a MyObject on the heap and save the address.
3. Call MyObject's constructor to initialize the memory.
4. Assign the saved address to o.

In C++ I would not have said, in step 1, "of type MyObject", because in C++ objects, references, and pointers are different addressable types. I would have said "of type reference to MyObject" or "of type pointer to MyObject." But in C# references limited independent addressability. You can only initialize them and assign to them. When you assign to them, unless the type refered to has defined assigment semantics, you are replacing the address of one object with the address of another (essentially, C# gurus don't flame me). Anything else you do operates through the reference on the object it refers to.

So what happens in method calls? Again this is something that I think C/C++ people have an easier time grasping. For a long time now microcomputers have passed arguments to methods in registers or on the stack. That is, when a method is called all the arguments to it are _copied to_ cpu registers or memory locations in the runtime stack. The called method then pops them off the stack or gets them from the registers and uses them. Two important things: 1) you can only pass scalar values or collections of scalar values (structs) on the stack (I am not sure whether an optimizing compiler will pass a small struct in registers); and 2) the values are copied to the stack. The originals stay where they are and are unaffected by whatever the called method does.

So how do you pass a complex object like, oh, FileStream to a method? By reference. A reference to an object is, internally, a scalar value. It's an address, and can be pushed onto the stack or into a register. In the called method, when that value is retrieved, whatever it done to it affects the object it refers to (see the rule about what you can do with references, above). That is, everything except assignment. If you take that reference in the called method, and you assign it to refer to another object, then allow the method to return, will the caller see that the reference it passed now refers to a new object?

The answer is no, it won't. Because the reference itself is a scalar value that was _copied to_ the stack or a register when the method is called. Changes to that reference in the called method act on the copy that was passed.

So to sum up, the ref keyword used with a scalar argument in a call to a method tells the compiler not to pass a copy of the value itself, but rather to create a reference to that value and pass that instead. The reference is anonymous, and you can't address it or manipulate it directly. But when you do something to it in the called method you are altering the original memory location that was passed by reference, and not a copy as would be the ordinary case.



 

RocksteadyDotNet

Diamond Member
Jul 29, 2008
3,152
1
0
Originally posted by: Rangoric
Anything related to pointers gets a bit complex.

(Another explanation)

--Prelude
There are 2 TYPES of objects.

You have Value types where the variable IS the object.
Then you have Reference types which only POINT at the object.

When you pass in a variable to a method, its value gets copied to the method.

For Values types, that means the OBJECT itself gets copied.
For Reference types, that means the thing that POINTS at the object gets copied.

a string is a Value Type, that IS a string, and when given to a method the OBJECT gets copied.

--Onto your example
So for:
public static void sr2(ref string str)
{
str = "Dee";
}

string hello = "Hello";
ClassData.sr2(ref hello);

In this example of yours we have a Value Type variable of hello, it has a value of "Hello".

What ref does is lets the method know that we want to know what happens to that variable. So instead of copying the object into the method, it gives the actual object to the method.

So that "ref string str" actually means "take what they give me and give it an alias of str". Whenever you have str in that method, it really means the variable 'hello' that you gave to it.

--To sum up
ref means "Here change this for me."
out means "Do you have an X for me?"
neither means "What can you do with this value?"

--Note
Reference Types (say you made a car class and have a variable of one like "Car vCar = new Car();") act differently and CAN be changed without a 'ref' in the method parameter. This is because you are only dealing with something that POINTS at the car, not the car itself. You would use ref if you wanted to change WHICH car it pointed at.

Err, a string in c# is a reference type.
 

bsobel

Moderator Emeritus<br>Elite Member
Dec 9, 2001
13,346
0
0
Err, a string in c# is a reference type.

True, but that doesn't mean the other poster is wrong. Remember, when you pass a string to a function in c# the function gets a copy. If you use the ref keyword the function gets the actual string object. So, without ref changes are local as they are done on the copy and discarded. With ref they are not local to the function called.
 

RocksteadyDotNet

Diamond Member
Jul 29, 2008
3,152
1
0
Originally posted by: bsobel
Err, a string in c# is a reference type.

True, but that doesn't mean the other poster is wrong. Remember, when you pass a string to a function in c# the function gets a copy. If you use the ref keyword the function gets the actual string object. So, without ref changes are local as they are done on the copy and discarded. With ref they are not local to the function called.

It's still ambiguous and he shouldn't have used a string in the example.

When you pass a string to a function it doesn't pass a copy of the string, it passes a reference to the string.

But when you do

myString = "New String"

it's creating a new instance of a string an assigning the reference to your variable.

Yeah, in practice it act justs like a value type, but you still shouldn't use it in examples for value types.
 

bsobel

Moderator Emeritus<br>Elite Member
Dec 9, 2001
13,346
0
0
When you pass a string to a function it doesn't pass a copy of the string, it passes a reference to the string.

Actually it creates a new copy on write wrapper and passes that, which itself contains the copy on write reference to the underlying string.

Yeah, in practice it act justs like a value type, but you still shouldn't use it in examples for value types.

It's in context based on the OP question. People simply started confusing ref parameters with reference objects.
 

Rangoric

Senior member
Apr 5, 2006
530
0
71
Originally posted by: RocksteadyDotNet
Err, a string in c# is a reference type.

string is a "reference" type only very technically (IE internally and mechanically but not to you). It acts like a value type, however, and for the purpose of this discussion is basically is a value type.