Wierd way C# passes in lists as arguments - c#

So i ran into this bug where C# behaves like i passed in a list by reference and not by value, like it usually does. Let me show an example:
using System;
using System.Collections.Generic;
namespace testprogram
{
class Program
{
static int x;
static List<Coordinate> coordinates;
static void Main(string[] args)
{
x = 10;
coordinates = new List<Coordinate>();
coordinates.Add(new Coordinate(0, 0));
coordinates.Add(new Coordinate(1, 1));
testfunction(x, coordinates);
Console.WriteLine(x);
foreach (var objekt in coordinates)
{
Console.WriteLine(objekt.xpos);
Console.WriteLine(objekt.ypos);
}
Console.Read();
}
static void testfunction(int test, List<Coordinate> objects)
{
test = 4;
foreach (Coordinate obj in objects)
{
obj.xpos = 4;
obj.ypos = 4;
}
}
}
class Coordinate
{
public int xpos;
public int ypos;
public Coordinate(int new_x, int new_y)
{
xpos = new_x;
ypos = new_y;
}
}
}
This code outputs:
10
4
4
4
4
But why? I expected it to be:
10
0
0
1
1
I tried to make an extra List in the Funktion and assign the value of the parameter to it but even that didn´t work. Is there some workaround for this?

The List<T> argument is a reference type which is passed by value.
If you modify any items in the list within the method, these will remain changed when you leave the method.
However, if you reassign the reference inside the method, these changes will be lost outside the method. If you want to pass a parameter by reference, you use the ref keyword:
static void testfunction(int test, ref List<Coordinate> objects)
{
// This will update objects outside the testfunction method
objects = new List<Coordinate>();
}
You can also use the out keyword, which works similar to the ref keyword. The only difference is that you don't have to initialise values that are passed in as out parameters before you call the method, and they must be initialised before leaving the method.
static void Main(string[] args)
{
// No need to initialise variable passed as "out" parameter
List<Coordinate> objects;
testfunction(test, out objects);
}
static void testfunction(int test, out List<Coordinate> objects)
{
// Removing this line would result in a compilation error
objects = new List<Coordinate>();
}

Your expectations are wrong. The list is passed as a value. It means that variable named objects is a value-copy of original list variable. But the list contains references, I mean the contents of the list are references to Coordinate objects. So if you would try to change the list variable like objects = new List<>(), it wouldn't change your original list. But if you change the objects inside the list, the changes are actually applied to the original list.
objects[0] = new Coordinate(5, 5);
objects[0].xpos = 6;
Both of these examples change the original list.
If you want to have the possibility to safely change anything in the list, you have to make a deep clone of it. You can use Clone() method, but it can be tricky, because you must manually clone each object inside the list. This was already answered here:
How create a new deep copy (clone) of a List<T>?

You passed a reference to the list "by value". So, if you change the reference "object" in "testfunction", then "coordinates" will not change (as a pointer). But changing the elements of "object" will affect the elements of "coordinates".

Related

How does the keyword `ref` affect memory management and garbage collection?

I am new to C# and I have been messing around with 'ref', 'out' and pointers, and I have a general question about how 'ref' works, especially when using objects and not primitive types. Say this is my method:
public void foo(ref Point p) {
p.set(1,1); // the x/y values are updated without constructing a new Point
}
and a similar method:
public void bar(Point p) {
p.set(1,1); // the x/y values are updated without constructing a new Point
}
EDIT: Point is a class in both cases
Both work, but is one more cost effective than the other? I know in C++ if you pass in a pointer you are only giving the memory address; from my understanding of C#, you cannot pass in an Object* into a method because of the automatic garbage collection. Does 'ref' pin an object to a location? Also, if you pass in an object to a method, like 'bar' above, is it passing a copy of the object or is it passing a pointer/reference?
Clarification: In my book I have, it does say if you want a method to update a primitive, such as int, you need to use ref (out if it is not initialized) or a *. I was asking if the same holds true for objects, and if passing an object as a parameter rather than a ref to an object costs more.
If your type is a struct, ref is roughly equivalent to a pointer to that struct. No new instances are created here. The difference (from passing it without ref) is that you can now mutate the original struct instance contained in that variable.
If your type is a class, ref simply adds one more level of indirection. No new instances are created here either. The difference (from passing it without ref) is that you can now entirely replace (not just mutate) the original class instance referenced by that variable with something else.
Since no new instances are created in either case, the garbage collector probably won't care about this in any important way.
In fact, class is a reference type, it mean that a variable of a reference type hold a reference to it's data instead of holding is data directly like value type.
When you pass a variable of a reference type as method parameter, it pass the reference to that data, not the data itself. So if update some properties of your object, the update is reflected in the original variable, except if you reassign the parameter.
Example from MSDN :
class PassingRefByVal
{
static void Change(int[] pArray)
{
pArray[0] = 888; // This change affects the original element.
pArray = new int[5] {-3, -1, -2, -3, -4}; // This change is local.
System.Console.WriteLine("Inside the method, the first element is: {0}", pArray[0]);
}
static void Main()
{
int[] arr = {1, 4, 5};
System.Console.WriteLine("Inside Main, before calling the method, the first element is: {0}", arr [0]);
Change(arr);
System.Console.WriteLine("Inside Main, after calling the method, the first element is: {0}", arr [0]);
}
}
/* Output:
Inside Main, before calling the method, the first element is: 1
Inside the method, the first element is: -3
Inside Main, after calling the method, the first element is: 888
*/
Passing a variable of a reference type with the ref keyword will reflect any change to the original variable, even if you reassin the parameter.
Example from MSDN :
class PassingRefByRef
{
static void Change(ref int[] pArray)
{
// Both of the following changes will affect the original variables:
pArray[0] = 888;
pArray = new int[5] {-3, -1, -2, -3, -4};
System.Console.WriteLine("Inside the method, the first element is: {0}", pArray[0]);
}
static void Main()
{
int[] arr = {1, 4, 5};
System.Console.WriteLine("Inside Main, before calling the method, the first element is: {0}", arr[0]);
Change(ref arr);
System.Console.WriteLine("Inside Main, after calling the method, the first element is: {0}", arr[0]);
}
}
/* Output:
Inside Main, before calling the method, the first element is: 1
Inside the method, the first element is: -3
Inside Main, after calling the method, the first element is: -3
*/
MSDN documentation.
Quick distinction between a class vs. a struct:
A class is a reference type. When an object of the class is created,
the variable to which the object is assigned holds only a reference to
that memory. When the object reference is assigned to a new variable,
the new variable refers to the original object. Changes made through
one variable are reflected in the other variable because they both
refer to the same data.
A struct is a value type. When a struct is
created, the variable to which the struct is assigned holds the
struct's actual data. When the struct is assigned to a new variable,
it is copied. The new variable and the original variable therefore
contain two separate copies of the same data. Changes made to one copy
do not affect the other copy.
https://msdn.microsoft.com/en-us/library/ms173109.aspx
Your example is tricky because in c# Point is an immutable struct, not an object.
Hopefully this example will help show what happens with structs and objects with and without ref.
public static void StructTest()
{
var fooStruct = new MyStruct();
var barStruct = new MyStruct();
Console.WriteLine(fooStruct.Value); // prints 0
Console.WriteLine(barStruct.Value); // prints 0
fooStruct(ref fooStruct);
barStruct(barStruct);
// Struct value only changes when passed by reference.
Console.WriteLine(fooStruct.Value); // prints 1
Console.WriteLine(barStruct.Value); // prints 0
}
public void fooStruct(ref MyStruct m)
{
m.Value++;
}
public void barStruct(MyStruct m)
{
m.Value++;
}
public static void ObjectTest()
{
var fooObject = new MyObject();
var barObject = new MyObject();
Console.WriteLine(fooObject.Value); // prints 0
Console.WriteLine(barObject.Value); // prints 0
fooObject(ref fooObject);
barObject(barObject);
// Objects are automatically passed by reference. No difference.
Console.WriteLine(fooObject.Value); // prints 1
Console.WriteLine(barObject.Value); // prints 1
fooSetObjectToNull(ref fooObject);
barSetObjectToNull(barObject);
// Reference is actually a pointer to the variable that holds a reference to the object.
Console.WriteLine(fooObject == null); // prints true
Console.WriteLine(barObject == null); // prints false
}
public void fooObject(ref MyObject m)
{
m.Value++;
}
public void barObject(ref MyObject m)
{
m.Value++;
}
public void fooSetObjectToNull(ref MyObject m)
{
m = null;
}
public void barSetObjectToNull(MyObject m)
{
m = null;
}

Type 'string' as an argument in C# function

The string type in C# is a reference type, and passing a reference type argument by value copies the reference so that I don't need to use the ref modifier. However, I need to use the ref modifier for modifying the input string. Why is this?
using System;
class TestIt
{
static void Function(ref string input)
{
input = "modified";
}
static void Function2(int[] val) // Don't need ref for reference type
{
val[0] = 100;
}
static void Main()
{
string input = "original";
Console.WriteLine(input);
Function(ref input); // Need ref to modify the input
Console.WriteLine(input);
int[] val = new int[10];
val[0] = 1;
Function2(val);
Console.WriteLine(val[0]);
}
}
The reason you need to ref the string parameter is that even though you pass in a reference to a string object, assigning something else to the parameter will just replace the reference currently stored in the parameter variable. In other words, you have changed what the parameter refers to, but the original object is unchanged.
When you ref the parameter, you have told the function that the parameter is actually an alias for the passed-in variable, so assigning to it will have the desired effect.
EDIT: Note that while string is an immutable reference type, that's not too relevant here. Since you're just trying to assign a new object (in this case the string object "modified"), your approach wouldn't work with any reference type. For example, consider this slight modification to your code:
using System;
class TestIt
{
static void Function(ref string input)
{
input = "modified";
}
static void Function2(int[] val) // don't need ref for reference type
{
val = new int[10]; // Change: create and assign a new array to the parameter variable
val[0] = 100;
}
static void Main()
{
string input = "original";
Console.WriteLine(input);
Function(ref input); // need ref to modify the input
Console.WriteLine(input);
int[] val = new int[10];
val[0] = 1;
Function2(val);
Console.WriteLine(val[0]); // This line still prints 1, not 100!
}
}
Now, the array test "fails", because you're assigning a new object to the non-ref parameter variable.
It helps to compare string to a type that is like string but is mutable. Let's see a short example with StringBuilder:
public void Caller1()
{
var builder = new StringBuilder("input");
Console.WriteLine("Before: {0}", builder.ToString());
ChangeBuilder(builder);
Console.WriteLine("After: {0}", builder.ToString());
}
public void ChangeBuilder(StringBuilder builder)
{
builder.Clear();
builder.Append("output");
}
This produces:
Before: input
After: output
So we see that for a mutable type, i.e. a type that can have its value modified, it is possible to pass a reference to that type to a method like ChangeBuilder and not use ref or out and still have the value changed after we called it.
And notice that at no time did we actually set builder to a different value in ChangeBuilder.
By contrast, if we do the same thing with string:
public void Caller2()
{
var s = "input";
Console.WriteLine("Before: {0}", s);
TryToChangeString(s);
Console.WriteLine("After: {0}", s);
}
public void TryToChangeString(string s)
{
s = "output";
}
This produces:
Before: input
After: input
Why? Because in TryToChangeString we are not actually changing the contents of the string referenced by the variable s, we are replacing s with an entirely new string. Furthermore, s is a local variable to TryToChangeString and so replacing the value of s inside the function has no effect on the variable that was passed in to the function call.
Because a string is immutable, there is no way, without using ref or out, to affect the callers string.
Finally, the last example does what we want with string:
public void Caller3()
{
var s = "input";
Console.WriteLine("Before: {0}", s);
ChangeString(ref s);
Console.WriteLine("After: {0}", s);
}
public void ChangeString(ref string s)
{
s = "output";
}
This produces:
Before: input
After: output
The ref parameter actually makes the two s variables aliases for each other. It's as though they were the same variable.
Strings are immutable - you are not modifying the string but replacing the object the reference points to with another one.
Compare that with e.g., a List: To add Items, you don't need ref. To replace the entire list with a different object, you need ref (or out).
This is the case for all immutable types. string happens to be immutable.
In order to change the immutable type outside of the method, you must change the reference. Therefore either ref or out is required to have an effect outside of the method.
Note: It's worth noting that in your example, you are calling out a particular case that does not match the other example: you are actually pointing to a different reference rather than simply changing the existing reference. As noted by dlev (and the Skeet himself in my comments), if you did the same for all other types (e.g., val = new int[1]), including mutable ones, then you will "lose" your changes once the method returns because they did not happen to the same object in memory, unless you use ref or out like you did with string above.
To hopefully clarify:
You are passing in a pointer that points to your object in memory. Without ref or out, a new pointer is made that points to the exact same location, and all changes happen using the copied pointer. Using them, the same pointer is used and all changes made to the pointer are reflected outside the method.
If your object is mutable, then that means that it can be changed without creating a new instance of the object. If you create a new instance, then you must point to somewhere else in memory, which means you must change your pointer.
Now, if your object is immutable, then that means that it cannot be changed without creating a new instance.
In your example, you created a new instance of a string (equal to "modified") and then changed the pointer (input) to point to that new instance. For the int array, you changed one of the 10 values effectively pointed to by val, which does not require messing with val's pointer--it simply goes to where you want (the first element of the array), and then modifies that first value, in-place.
A more similar example would be (stolen from dlev, but this is how to make them truly comparable):
static void Function(ref string input)
{
input = "modified";
}
static void Function2(int[] val)
{
val = new int[1];
val[0] = 100;
}
Both functions change their parameter's pointer. Only because you used ref does input "remember" its changes, because when it changes the pointer, it is changing the pointer that was passed in and not just a copy of it.
val will still be an array of 10 ints outside of the function, and val[0] will still be 1 because the "val" within Function2 is a different pointer that originally points to the same location as Main's val, but it points somewhere else after the new array is created (the different pointer points to the new array, and the original pointer continues to point to the same location).
If I used ref with the int array, then it to would have changed. And it would have changed in size too.
A better example for newbies:
string a = "one";
string b = a;
string b = "two";
Console.WriteLine(a);
... will output "one".
Why? Because you are assigning a whole new string into pointer b.
The confusion is that ref type references are passed by value by default, to modify the reference itself (what the object points to) you have to pass the reference by reference - using ref.
In your case you are handling strings - assigning a string to a variable (or appending to, etc.) changes the reference, since strings are immutable there is no way to avoid this either, so you have to use ref.
You're right. Arrays and strings are reference types. But if to be honest and compare similar behavior you should write something like this:
static void Function2(int[] val) // It doesn't need 'ref' for a reference type
{
val = new[] { 1, 2, 3, 4 };
}
But in your example you perform a write operation in some element of a C# one-dimensional array via reference val.

Use of 'ref' keyword in C# [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicates:
Why use ref keyword when passing an Object?
When to pass ref keyword in
What is the correct usage of the 'ref' keyword in C#. I believe there has been plenty of discussion threads on this, but what is not clear to me is:
Is the ref keyword required if you are passing in a reference object? I mean when you create an object in the heap, is it not always passed by reference. Does this have to be explicitly marked as a ref?
Using ref means that the reference is passed to the function.
The default behaviour is that the function receives a new reference to the same object. This means if you change the value of the reference (e.g. set it to a new object) then you are no longer pointing to the original, source object. When you pass using ref then changing the value of the reference changes the source reference - because they are the same thing.
Consider this:
public class Thing
{
public string Property {get;set;}
}
public static void Go(Thing thing)
{
thing = new Thing();
thing.Property = "Changed";
}
public static void Go(ref Thing thing)
{
thing = new Thing();
thing.Property = "Changed";
}
Then if you run
var g = new Thing();
// this will not alter g
Go(g);
// this *will* alter g
Go(ref g);
There is a lot of confusing misinformation in the answers here. The easiest way to understand this is to abandon the idea that "ref" means "by reference". A better way to think about it is that "ref" means "I want this formal parameter on the callee side to be an alias for a particular variable on the caller side".
When you say
void M(ref int y) { y = 123; }
...
int x = 456;
M(ref x);
that is saying "during the call to M, the formal parameter y on the callee side is another name for the variable x on the caller side". Assigning 123 to y is exactly the same as assigning 123 to x because they are the same variable, a variable with two names.
That's all. Don't think about reference types or value types or whatever, don't think about passing by reference or passing by value. All "ref" means is "temporarily make a second name for this variable".
I believe the ref keyword indicates that you are passing the object by reference, not by value. For example:
void myfunction(ref object a) {
a = new Something();
}
would change the value of a in the calling function
However,
void myfunction(object a) {
a = new Something();
}
would change the value of a locally, but not in the calling function. You can still change PROPERTIES of the item, but you cannot set the value of the item itself. For example;
a.someproperty = value;
would work in both cases.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace InOutRef
{
static class InOutRef
{
public static void In(int i)
{
Console.WriteLine(i);
i=100;
Console.WriteLine(i);
}
public static void Ref(ref int i)
{
Console.WriteLine(i);
i=200;
Console.WriteLine(i);
}
public static void Out(out int i)
{
//Console.WriteLine(i); //Error Unsigned Ref
i=300;
Console.WriteLine(i);
}
}
class Program
{
static void Main(string[] args)
{
int i = 1;
InOutRef.In(i); //passed by value (in only)
Debug.Assert(i==1);
InOutRef.Ref(ref i); //passed by ref (in or out)
Debug.Assert(i == 200);
InOutRef.Out(out i); //passed by as out ref (out only)
Debug.Assert(i == 300);
}
}
}
I can't be any more literal on my answer. The code will not remember reference chanages such as the classic Java swap question when using in. However, when using ref, it will be similar to VB.NET as it will remember the changes in and out. If you use the out parameter it means that it must be declared before you return (this is enforced by the compiler).
Output:
1 //1 from main
100 //100 from in
1 //1 is NOT remembered from In
200 //200 from ref
//should be 200 here but out enforces out param (not printed because commented out)
300 //300 is out only
Press any key to continue . . .

List Collection object as Method Parameter

Can anyone explain how the memory allocation is done while invoking a method having list collection as parameter. Since the code snippet below though apparently seems to result same but it is not resulting same.
So I would like to know the difference in both the method call in terms of memory allocation.
using System;
using System.Collections.Generic;
namespace ListSample
{
class ListSampleClass
{
static void Main(string[] args)
{
List<int> i = new List<int>();
i.Add(10);
i.Add(15);
SampleMethod1(i);
Console.WriteLine("Result of SampleMethod1:"+i[0]);
SampleMethod2(i);
Console.WriteLine("Result of SampleMethod2:" + i[0]);
Console.ReadKey();
}
public static void SampleMethod1(List<int> i)
{
List<int> j = new List<int>();
j.Insert(0,20);
i = j;
}
public static void SampleMethod2(List<int> i)
{
List<int> j = new List<int>();
j = i;
j.Insert(0, 20);
}
}
}
Unless you specify ref or out, parameters are passed by value. For reference types, that means a reference to the object (the List<int> in this case) is passed by value.
"Pass by value" means that the argument (the expression in the calling statement) is evaluated, and then the resulting value is copied into the parameter (the variable listed in the method signature). Any further changes to the parameter, in terms of assigning it a new value, are not seen by the caller. (But keep reading...)
That means that in your first method call:
public static void SampleMethod1(List<int> i)
{
List<int> j = new List<int>();
j.Insert(0,20);
i = j;
}
you're creating a new list, inserting a value into it, and then copying the reference to that new list to i - but that has no effect at all. The parameter is effectively just another local variable - a change to the value of the variable itself doesn't affect the caller.
Now compare that with your second method:
public static void SampleMethod2(List<int> i)
{
List<int> j = new List<int>();
j = i;
j.Insert(0, 20);
}
This creates a new list and then immediately ignores it, instead assigning the reference to the list passed in (as i) to j. It then inserts a value into the list. The net result of this method is that a value is inserted into the list. It's equivalent to:
public static void SampleMethod2(List<int> i)
{
i.Insert(0, 20);
}
Note that this is not changing the value of the parameter. It's making a change to the object that the value of the parameter refers to. This is a crucial difference to understand.
I have an article on parameter passing and another one on reference and value types which may help you understand this more.

Why Can I Change Struct's int[] Property from Method Without Specifying "ref"?

From a method, I can pass a struct which contains an array of integers, and change the values in the array. I am not sure I understand fully why I can do this. Can someone please explain why I can change the values stored in the int[]?
private void DoIt(){
SearchInfo a = new SearchInfo();
a.Index = 1;
a.Map = new int[] { 1 };
SearchInfo b = new SearchInfo();
b.Index = 1;
b.Map = new int[] { 1 };
ModifyA(a);
ModifyB(ref b);
Debug.Assert(a.Index == 1);
Debug.Assert(a.Map[0] == 1, "why did this change?");
Debug.Assert(b.Index == 99);
Debug.Assert(b.Map[0] == 99);
}
void ModifyA(SearchInfo a) {
a.Index = 99;
a.Map[0] = 99;
}
void ModifyB(ref SearchInfo b) {
b.Index = 99;
b.Map[0] = 99;
}
struct SearchInfo {
public int[] Map;
public int Index;
}
In C#, references are passed by value. An array is not copied when passed to method or when stored in an instance of another class. - a reference to the array is passed. This means a method which recieves a reference to an array (either directly or as part of another object) can modify the elements of that array.
Unlike languages like C++, you cannot declare "immutable" arrays in C# - you can however uses classes like List which have readonly wrappers available to prevent modification to the collection.
From a method, I can pass a struct which contains an array of integers, and change the values in the array. I am not sure I understand fully why I can do this.
An array is defined as a collection of variables.
Variables, by definition, can be changed. That is why we call them "variables".
Therefore when you pass an array, you can change the contents; the contents of an array are variables.
Why can I change a struct’s int[] property without specifying “ref”?
Remember, as we discussed before in a different question, you use ref to make an alias to a variable. That is what "ref" is for -- making aliases to variables. (It is unfortunate that the keyword is the confusing "ref" -- it probably would have been more clear to make it "alias".)
From MSDN:
Do not return an internal instance of an array. This allows calling code to change the array. The following example demonstrates how the array badChars can be changed by any code that accesses the Path property even though the property does not implement the set accessor.
using System;
using System.Collections;
public class ExampleClass
{
public sealed class Path
{
private Path(){}
private static char[] badChars = {'\"', '<', '>'};
public static char[] GetInvalidPathChars()
{
return badChars;
}
}
public static void Main()
{
// The following code displays the elements of the
// array as expected.
foreach(char c in Path.GetInvalidPathChars())
{
Console.Write(c);
}
Console.WriteLine();
// The following code sets all the values to A.
Path.GetInvalidPathChars()[0] = 'A';
Path.GetInvalidPathChars()[1] = 'A';
Path.GetInvalidPathChars()[2] = 'A';
// The following code displays the elements of the array to the
// console. Note that the values have changed.
foreach(char c in Path.GetInvalidPathChars())
{
Console.Write(c);
}
}
}
You cannot correct the problem in the preceding example by making the badChars array readonly (ReadOnly in Visual Basic). You can clone the badChars array and return the copy, but this has significant performance implications.
Although your SearchInfo struct is a value type, the .Map field is holding a reference, because Array is a reference type. Think of this reference as the address pointing to the memory location where the array resides.
When you pass an instance of SearchInfo to a method, as you know, the SearchInfo gets copied. And the copy naturally contains the very same address pointing to the very same array.
In other words, copying the struct doesn't make a copy of the array, it just makes a copy of the pointer.
Well, it is passed by reference anyway, like all reference types in C#.
Neither C# nor CLR support constness, unfortunately, so the platform doesn't really know if you are allowed to change it or not. So, it has the reference, it may use it to change the value, and there's nothing to stop it from doing so.
You may see it as a language design bug, btw. It is unexpected for the user.

Categories