IList and Reference Types in C# [modified]
-
I was working on some code earlier today and found what appears to be a bug in how IList is handled in C#... The following code seems to me to produce the wrong output:
public void foo(IList listOfNumbers)
{
listOfNumbers = new List<int>();
listOfNumbers.Add(1);
listOfNumbers.Add(2);
listOfNumbers.Add(3);
}public void test()
{
IList listOfNumbers = new List<int>();
listOfNumbers.Add(10);foo(listOfNumbers); MessageBox.Show(listOfNumbers\[0\].ToString());
}
Now I would expect that with IList being a reference type, when the call to foo is made, the reference to listOfNumbers is lost, and a new one is created. But it seems that the list keeps it's own reference as the message box shows "10" where I would have expected "1". Anyway, the fix I found was to use the
ref
keyword like so:public void foo(ref IList listOfNumbers)
{
listOfNumbers = new List<int>();
listOfNumbers.Add(1);
listOfNumbers.Add(2);
listOfNumbers.Add(3);
}public void test()
{
IList listOfNumbers = new List<int>();
listOfNumbers.Add(10);foo(ref listOfNumbers); MessageBox.Show(listOfNumbers\[0\].ToString());
}
Here the result is now "1" which is what I had expected in both cases... I don't know why this is, but I'm guessing this is maybe compiler bug, or maybe there is some strangeness going on when you pass an interface, but I just thought I'd share this with you as it frustrated a couple of us for a few minutes today! Chris [Edit: I stand corrected! The compiler is producing the correct behaviour, as it passes the pointer by value - i.e. changes to the object would be kept (like List.Add), but changes to the pointer would not (i.e. referencing a new object). Thanks to everybody who pointed this out :) ]
modified on Thursday, September 25, 2008 4:22 AM
-
I was working on some code earlier today and found what appears to be a bug in how IList is handled in C#... The following code seems to me to produce the wrong output:
public void foo(IList listOfNumbers)
{
listOfNumbers = new List<int>();
listOfNumbers.Add(1);
listOfNumbers.Add(2);
listOfNumbers.Add(3);
}public void test()
{
IList listOfNumbers = new List<int>();
listOfNumbers.Add(10);foo(listOfNumbers); MessageBox.Show(listOfNumbers\[0\].ToString());
}
Now I would expect that with IList being a reference type, when the call to foo is made, the reference to listOfNumbers is lost, and a new one is created. But it seems that the list keeps it's own reference as the message box shows "10" where I would have expected "1". Anyway, the fix I found was to use the
ref
keyword like so:public void foo(ref IList listOfNumbers)
{
listOfNumbers = new List<int>();
listOfNumbers.Add(1);
listOfNumbers.Add(2);
listOfNumbers.Add(3);
}public void test()
{
IList listOfNumbers = new List<int>();
listOfNumbers.Add(10);foo(ref listOfNumbers); MessageBox.Show(listOfNumbers\[0\].ToString());
}
Here the result is now "1" which is what I had expected in both cases... I don't know why this is, but I'm guessing this is maybe compiler bug, or maybe there is some strangeness going on when you pass an interface, but I just thought I'd share this with you as it frustrated a couple of us for a few minutes today! Chris [Edit: I stand corrected! The compiler is producing the correct behaviour, as it passes the pointer by value - i.e. changes to the object would be kept (like List.Add), but changes to the pointer would not (i.e. referencing a new object). Thanks to everybody who pointed this out :) ]
modified on Thursday, September 25, 2008 4:22 AM
-
I was working on some code earlier today and found what appears to be a bug in how IList is handled in C#... The following code seems to me to produce the wrong output:
public void foo(IList listOfNumbers)
{
listOfNumbers = new List<int>();
listOfNumbers.Add(1);
listOfNumbers.Add(2);
listOfNumbers.Add(3);
}public void test()
{
IList listOfNumbers = new List<int>();
listOfNumbers.Add(10);foo(listOfNumbers); MessageBox.Show(listOfNumbers\[0\].ToString());
}
Now I would expect that with IList being a reference type, when the call to foo is made, the reference to listOfNumbers is lost, and a new one is created. But it seems that the list keeps it's own reference as the message box shows "10" where I would have expected "1". Anyway, the fix I found was to use the
ref
keyword like so:public void foo(ref IList listOfNumbers)
{
listOfNumbers = new List<int>();
listOfNumbers.Add(1);
listOfNumbers.Add(2);
listOfNumbers.Add(3);
}public void test()
{
IList listOfNumbers = new List<int>();
listOfNumbers.Add(10);foo(ref listOfNumbers); MessageBox.Show(listOfNumbers\[0\].ToString());
}
Here the result is now "1" which is what I had expected in both cases... I don't know why this is, but I'm guessing this is maybe compiler bug, or maybe there is some strangeness going on when you pass an interface, but I just thought I'd share this with you as it frustrated a couple of us for a few minutes today! Chris [Edit: I stand corrected! The compiler is producing the correct behaviour, as it passes the pointer by value - i.e. changes to the object would be kept (like List.Add), but changes to the pointer would not (i.e. referencing a new object). Thanks to everybody who pointed this out :) ]
modified on Thursday, September 25, 2008 4:22 AM
Seems correct to me.
-
I was working on some code earlier today and found what appears to be a bug in how IList is handled in C#... The following code seems to me to produce the wrong output:
public void foo(IList listOfNumbers)
{
listOfNumbers = new List<int>();
listOfNumbers.Add(1);
listOfNumbers.Add(2);
listOfNumbers.Add(3);
}public void test()
{
IList listOfNumbers = new List<int>();
listOfNumbers.Add(10);foo(listOfNumbers); MessageBox.Show(listOfNumbers\[0\].ToString());
}
Now I would expect that with IList being a reference type, when the call to foo is made, the reference to listOfNumbers is lost, and a new one is created. But it seems that the list keeps it's own reference as the message box shows "10" where I would have expected "1". Anyway, the fix I found was to use the
ref
keyword like so:public void foo(ref IList listOfNumbers)
{
listOfNumbers = new List<int>();
listOfNumbers.Add(1);
listOfNumbers.Add(2);
listOfNumbers.Add(3);
}public void test()
{
IList listOfNumbers = new List<int>();
listOfNumbers.Add(10);foo(ref listOfNumbers); MessageBox.Show(listOfNumbers\[0\].ToString());
}
Here the result is now "1" which is what I had expected in both cases... I don't know why this is, but I'm guessing this is maybe compiler bug, or maybe there is some strangeness going on when you pass an interface, but I just thought I'd share this with you as it frustrated a couple of us for a few minutes today! Chris [Edit: I stand corrected! The compiler is producing the correct behaviour, as it passes the pointer by value - i.e. changes to the object would be kept (like List.Add), but changes to the pointer would not (i.e. referencing a new object). Thanks to everybody who pointed this out :) ]
modified on Thursday, September 25, 2008 4:22 AM
The MS behavior is correct. When dealing with object parameters l-value and r-values seem to have strange behavior until you are used to it.
Need software developed? Offering C# development all over the United States, ERL GLOBAL, Inc is the only call you will have to make.
Happiness in intelligent people is the rarest thing I know. -- Ernest Hemingway
Most of this sig is for Google, not ego. -
I was working on some code earlier today and found what appears to be a bug in how IList is handled in C#... The following code seems to me to produce the wrong output:
public void foo(IList listOfNumbers)
{
listOfNumbers = new List<int>();
listOfNumbers.Add(1);
listOfNumbers.Add(2);
listOfNumbers.Add(3);
}public void test()
{
IList listOfNumbers = new List<int>();
listOfNumbers.Add(10);foo(listOfNumbers); MessageBox.Show(listOfNumbers\[0\].ToString());
}
Now I would expect that with IList being a reference type, when the call to foo is made, the reference to listOfNumbers is lost, and a new one is created. But it seems that the list keeps it's own reference as the message box shows "10" where I would have expected "1". Anyway, the fix I found was to use the
ref
keyword like so:public void foo(ref IList listOfNumbers)
{
listOfNumbers = new List<int>();
listOfNumbers.Add(1);
listOfNumbers.Add(2);
listOfNumbers.Add(3);
}public void test()
{
IList listOfNumbers = new List<int>();
listOfNumbers.Add(10);foo(ref listOfNumbers); MessageBox.Show(listOfNumbers\[0\].ToString());
}
Here the result is now "1" which is what I had expected in both cases... I don't know why this is, but I'm guessing this is maybe compiler bug, or maybe there is some strangeness going on when you pass an interface, but I just thought I'd share this with you as it frustrated a couple of us for a few minutes today! Chris [Edit: I stand corrected! The compiler is producing the correct behaviour, as it passes the pointer by value - i.e. changes to the object would be kept (like List.Add), but changes to the pointer would not (i.e. referencing a new object). Thanks to everybody who pointed this out :) ]
modified on Thursday, September 25, 2008 4:22 AM
this is no bug! passing reference types by value, results in you beeing able to change their content but not to change the address of it in memory! so if you pass your list to foo and add some new elemts there, they will be added to the original list. but if you create a new list and assign it to your parameter, the only outcome will be, that you lose your connection to the passed reference! this behaivor is just like passing ponters and pointers to pointers in c++ but as you dont use pointers in c# (or at least you dont see the compiler using it :-) ) it's the only possibility to implement it. i hope this helps greets
-
this is no bug! passing reference types by value, results in you beeing able to change their content but not to change the address of it in memory! so if you pass your list to foo and add some new elemts there, they will be added to the original list. but if you create a new list and assign it to your parameter, the only outcome will be, that you lose your connection to the passed reference! this behaivor is just like passing ponters and pointers to pointers in c++ but as you dont use pointers in c# (or at least you dont see the compiler using it :-) ) it's the only possibility to implement it. i hope this helps greets
-
I was working on some code earlier today and found what appears to be a bug in how IList is handled in C#... The following code seems to me to produce the wrong output:
public void foo(IList listOfNumbers)
{
listOfNumbers = new List<int>();
listOfNumbers.Add(1);
listOfNumbers.Add(2);
listOfNumbers.Add(3);
}public void test()
{
IList listOfNumbers = new List<int>();
listOfNumbers.Add(10);foo(listOfNumbers); MessageBox.Show(listOfNumbers\[0\].ToString());
}
Now I would expect that with IList being a reference type, when the call to foo is made, the reference to listOfNumbers is lost, and a new one is created. But it seems that the list keeps it's own reference as the message box shows "10" where I would have expected "1". Anyway, the fix I found was to use the
ref
keyword like so:public void foo(ref IList listOfNumbers)
{
listOfNumbers = new List<int>();
listOfNumbers.Add(1);
listOfNumbers.Add(2);
listOfNumbers.Add(3);
}public void test()
{
IList listOfNumbers = new List<int>();
listOfNumbers.Add(10);foo(ref listOfNumbers); MessageBox.Show(listOfNumbers\[0\].ToString());
}
Here the result is now "1" which is what I had expected in both cases... I don't know why this is, but I'm guessing this is maybe compiler bug, or maybe there is some strangeness going on when you pass an interface, but I just thought I'd share this with you as it frustrated a couple of us for a few minutes today! Chris [Edit: I stand corrected! The compiler is producing the correct behaviour, as it passes the pointer by value - i.e. changes to the object would be kept (like List.Add), but changes to the pointer would not (i.e. referencing a new object). Thanks to everybody who pointed this out :) ]
modified on Thursday, September 25, 2008 4:22 AM
c2423 wrote:
Now I would expect that with IList being a reference type, when the call to foo is made, the reference to listOfNumbers is lost, and a new one is created.
A reference type means that
listOfNumbers
is a reference to an unnamed object on the managed heap. If you make a change to the object itself, the change will be visible in the outer function. However, the reference itself is passed to the function by value, unless you useref
keyword, so within the function you have a copy of the original reference that points to the same object. If you change the object the reference is pointing to, the original reference will not be affected by it. -
c2423 wrote:
Now I would expect that with IList being a reference type, when the call to foo is made, the reference to listOfNumbers is lost, and a new one is created.
A reference type means that
listOfNumbers
is a reference to an unnamed object on the managed heap. If you make a change to the object itself, the change will be visible in the outer function. However, the reference itself is passed to the function by value, unless you useref
keyword, so within the function you have a copy of the original reference that points to the same object. If you change the object the reference is pointing to, the original reference will not be affected by it. -
I was working on some code earlier today and found what appears to be a bug in how IList is handled in C#... The following code seems to me to produce the wrong output:
public void foo(IList listOfNumbers)
{
listOfNumbers = new List<int>();
listOfNumbers.Add(1);
listOfNumbers.Add(2);
listOfNumbers.Add(3);
}public void test()
{
IList listOfNumbers = new List<int>();
listOfNumbers.Add(10);foo(listOfNumbers); MessageBox.Show(listOfNumbers\[0\].ToString());
}
Now I would expect that with IList being a reference type, when the call to foo is made, the reference to listOfNumbers is lost, and a new one is created. But it seems that the list keeps it's own reference as the message box shows "10" where I would have expected "1". Anyway, the fix I found was to use the
ref
keyword like so:public void foo(ref IList listOfNumbers)
{
listOfNumbers = new List<int>();
listOfNumbers.Add(1);
listOfNumbers.Add(2);
listOfNumbers.Add(3);
}public void test()
{
IList listOfNumbers = new List<int>();
listOfNumbers.Add(10);foo(ref listOfNumbers); MessageBox.Show(listOfNumbers\[0\].ToString());
}
Here the result is now "1" which is what I had expected in both cases... I don't know why this is, but I'm guessing this is maybe compiler bug, or maybe there is some strangeness going on when you pass an interface, but I just thought I'd share this with you as it frustrated a couple of us for a few minutes today! Chris [Edit: I stand corrected! The compiler is producing the correct behaviour, as it passes the pointer by value - i.e. changes to the object would be kept (like List.Add), but changes to the pointer would not (i.e. referencing a new object). Thanks to everybody who pointed this out :) ]
modified on Thursday, September 25, 2008 4:22 AM
-
Passing by value means passing a copy of whatever object. Passing by reference is passing physical object itself .
Hey I would like to suggest reading C# in depth. This will answer many of the questions you will have including this one in depth. I bought it and really enjoyed reading it. Give it a try :)
At university studying Software Engineering - if i say this line to girls i find they won't talk to me Dan
-
I'm not sure I completely understand you - did you say C# can not use pointers? Pointers are available in C# if you use the "unsafe" keyword
-
What he means is that in C# you don't use pointers to pass in a parameter by reference, instead you use the ref keyword. Under the hood it is still using a pointer. Bill W
Just because code works, it doesn't mean that it is good code.
Why "do you not use pointers"? Sure it's ugly, but you Can use raw pointers, don't pretend that you can't That, was my point. edit: and what's with the 1 votes, look at this:
Goran Lastro wrote:
it's the only possibility to implement it
And then compare that to The Reality(tm) which is that you can use real pointers so it isn't the only way to implement it.
modified on Monday, October 20, 2008 1:50 PM
-
I was working on some code earlier today and found what appears to be a bug in how IList is handled in C#... The following code seems to me to produce the wrong output:
public void foo(IList listOfNumbers)
{
listOfNumbers = new List<int>();
listOfNumbers.Add(1);
listOfNumbers.Add(2);
listOfNumbers.Add(3);
}public void test()
{
IList listOfNumbers = new List<int>();
listOfNumbers.Add(10);foo(listOfNumbers); MessageBox.Show(listOfNumbers\[0\].ToString());
}
Now I would expect that with IList being a reference type, when the call to foo is made, the reference to listOfNumbers is lost, and a new one is created. But it seems that the list keeps it's own reference as the message box shows "10" where I would have expected "1". Anyway, the fix I found was to use the
ref
keyword like so:public void foo(ref IList listOfNumbers)
{
listOfNumbers = new List<int>();
listOfNumbers.Add(1);
listOfNumbers.Add(2);
listOfNumbers.Add(3);
}public void test()
{
IList listOfNumbers = new List<int>();
listOfNumbers.Add(10);foo(ref listOfNumbers); MessageBox.Show(listOfNumbers\[0\].ToString());
}
Here the result is now "1" which is what I had expected in both cases... I don't know why this is, but I'm guessing this is maybe compiler bug, or maybe there is some strangeness going on when you pass an interface, but I just thought I'd share this with you as it frustrated a couple of us for a few minutes today! Chris [Edit: I stand corrected! The compiler is producing the correct behaviour, as it passes the pointer by value - i.e. changes to the object would be kept (like List.Add), but changes to the pointer would not (i.e. referencing a new object). Thanks to everybody who pointed this out :) ]
modified on Thursday, September 25, 2008 4:22 AM
this is the normal behavior in the C# like to the ECMA I didnt understand why you crawled with.. ;P
-
I was working on some code earlier today and found what appears to be a bug in how IList is handled in C#... The following code seems to me to produce the wrong output:
public void foo(IList listOfNumbers)
{
listOfNumbers = new List<int>();
listOfNumbers.Add(1);
listOfNumbers.Add(2);
listOfNumbers.Add(3);
}public void test()
{
IList listOfNumbers = new List<int>();
listOfNumbers.Add(10);foo(listOfNumbers); MessageBox.Show(listOfNumbers\[0\].ToString());
}
Now I would expect that with IList being a reference type, when the call to foo is made, the reference to listOfNumbers is lost, and a new one is created. But it seems that the list keeps it's own reference as the message box shows "10" where I would have expected "1". Anyway, the fix I found was to use the
ref
keyword like so:public void foo(ref IList listOfNumbers)
{
listOfNumbers = new List<int>();
listOfNumbers.Add(1);
listOfNumbers.Add(2);
listOfNumbers.Add(3);
}public void test()
{
IList listOfNumbers = new List<int>();
listOfNumbers.Add(10);foo(ref listOfNumbers); MessageBox.Show(listOfNumbers\[0\].ToString());
}
Here the result is now "1" which is what I had expected in both cases... I don't know why this is, but I'm guessing this is maybe compiler bug, or maybe there is some strangeness going on when you pass an interface, but I just thought I'd share this with you as it frustrated a couple of us for a few minutes today! Chris [Edit: I stand corrected! The compiler is producing the correct behaviour, as it passes the pointer by value - i.e. changes to the object would be kept (like List.Add), but changes to the pointer would not (i.e. referencing a new object). Thanks to everybody who pointed this out :) ]
modified on Thursday, September 25, 2008 4:22 AM
:wtf: , - Read the docu about the ref-keyword! This is what I'd do before I post "strange behaviour/bug" here....