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?
Sp
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);
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();
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?
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.
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>
.
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.