views:

232

answers:

6

Passing Value Type parameters to functions in c# is by value unless you use the ref or out keyword on the parameter. But does this also apply to Reference Types?

Specifically I have a function that takes an IList<Foo>. Will the list passed to my function be a copy of the list with copy of its contained objects? Or will modifications to the list also apply for the caller? If so - Is there a clever way I can go about passing a copy?

public void SomeFunction()
{
    IList<Foo> list = new List<Foo>();
    list.Add(new Foo()); 
    DoSomethingWithCopyOfTheList(list);
    ..
}

public void DoSomethingWithCopyOfTheList(IList<Foo> list)
{
    // Do something
}
+1  A: 

The list is passed by reference, so if you modify the list in SomeFunction, you modify the list for the caller as well.

You can create a copy of a list by creating a new one:

var newList = new List<Foo>(oldList);
Mark Seemann
+10  A: 

All parameters are passed by value unless you explicitly use ref or out. However, when you pass an instance of a reference type, you pass the reference by value. I.e. the reference itself is copied, but since it is still pointing to the same instance, you can still modify the instance through this reference. I.e. the instance is not copied. The reference is.

If you want to make a copy of the list itself, List<T> has a handy constructor, that takes an IEnumerable<T>.

Brian Rasmussen
Additionally if you change the reference inside the body of the function this change will not be visible at the caller. +1 from me.
Aggelos Mpimpoudis
@Aggelos: Exactly. That is a property of pass by value.
Brian Rasmussen
+1  A: 

your list is passed by reference. If you want to pass a copy of the list you can do:

IList<Foo> clone = new List<Foo>(list);

if you add/remove elements in clone it won't modify list but the modifications of the elements themselves will be taken into account in both lists.

PierrOz
+1  A: 

When you pass reference type by value (without ref or out keywords) you may modify this reference type inside this method and all changes will reflect to callers code.

To solve your problem you may explicitly create a copy and pass this copy to your function, or you may use:

list.AsReadOnly();
Sergey Teplyakov
+2  A: 

When passing reference types, you pass the reference. This is an important concept.

If you pass a reference

byref, you pass the reference (pointer) directly.

byval, you pass a copy of the reference (pointer).

A reference is not the instance referenced. A reference is analagous to a pointer.

To pass a copy of the instance of a referencetype, you first must make a copy yourself and pass a reference to the copy. As such then you will not be modifying the original instance.

MaLio
I doubt you could have put it in a more confusing way..
Blindy
is that any better?
MaLio
+6  A: 

You're not alone; this confuses a lot of people.

Here's how I like to think of it.

A variable is a storage location.

A variable can store something of a particular type.

There are two kinds of types: value types and reference types.

The value of a variable of reference type is a reference to an object of that type.

The value of a variable of value type is an object of that type.

A formal parameter is a kind of variable.

There are three kinds of formal parameters: value parameters, ref parameters, and out parameters.

When you use a variable as an argument corresponding to a value parameter, the value of the variable is copied into the storage associated with the formal parameter. If the variable is of value type, then a copy of the value is made. If the variable is of reference type, then a copy of the reference is made, and the two variables now refer to the same object. Either way, a copy of the value of the variable is made.

When you use a variable as an argument corresponding to an out or ref parameter the parameter becomes an alias for the variable. When you say:

void M(ref int x) { ...}
...
int y = 123;
M(ref y);

what you are saying is "x and y now are the same variable". They both refer to the same storage location.

I find that much easier to comprehend than thinking about how the alias is actually implemented -- by passing the managed address of the variable to the formal parameter.

Is that clear?

Eric Lippert
Super clear! Thanks :-)
stiank81