4
public class Foo
{
    public static List<long> myList = new List<long>() { 1,2,3 }
}

In another method:

var testList = Foo.myList;

If I put a breakpoint at the last line and inspect testList it gives me different lengths from time to time.

When I use ToList() on Foo.myList it seems to behave correctly. But why?

Edit:

My problem was that I made an ajax call > modified Foo.myList > new ajax call > fetched Foo.myList again and got the modified value.

Johan
  • 35,120
  • 54
  • 178
  • 293
  • 2
    Because you did modify it in another method? Check all Add/Remove calls to it and where you pass the reference around. Were items added or removed from it? That could help to narrow down the issue. To be on the safe side you can make it a propery which does return a copy of the list so you can be sure that nobody does modify it by accident. – Alois Kraus Jun 30 '13 at 17:24
  • If you are not sure you can derive from List and override the Add and Remove methods to throw execeptions. Then replace your List with your ReadOnlyList. This will give you direct insights where there modification is happening. – Alois Kraus Jun 30 '13 at 17:52

2 Answers2

8

Race condition on shared state. The static field member means there's one copy, so if you manipulate the list in your code, it changes for ALL threads using the property. ToList() works because it creates a copy of the list which won't alter the original list, but note that this copy also points to the same objects as the original list if the objects are reference types. Therefore altering the reference types in the copy would also alter the values in the original list... but since long is a value type that won't apply here.

If you want your list to be read-only http://msdn.microsoft.com/en-us/library/e78dcd75.aspx

Haney
  • 32,775
  • 8
  • 59
  • 68
  • 1
    Ok, I was pretty sure that I didn't modify it. But I'll investigate the code again with this in mind. Thank you – Johan Jun 30 '13 at 17:38
  • If it's changing, you modified it. :D – Haney Jun 30 '13 at 17:38
  • I right clicked `Foo.myList` > "find usages". Result: "this is the only usage"... – Johan Jun 30 '13 at 17:48
  • 1
    Ok, so I found the problem. Even though I make 2 separate ajax calls, the state of `Foo.myList` seems to be saved. I had no idea about this :) – Johan Jun 30 '13 at 17:54
3

It sounds like you're modifying Foo.myList or a reference to it somewhere. Note that assigning the list to a local variable does not make a copy. Thus:

var list = new List<long> { 1, 2, 3 };
var testList = list;
testList.Add(4); // list is now [1, 2, 3, 4]
list.Add(5); // testList is now [1, 2, 3, 4, 5]

ToList(), on the other hand, makes a copy. In general, it's probably safest to make any static lists read only (if that's the semantics you want) to prevent this from happening accidentally:

public class Foo {
    // pre .NET 4.5, use ReadOnlyCollection<T> (which implements IList<T>)
    public static readonly IReadOnlyList<long> myList = new List<long> { 1, 2, 3 }.AsReadOnly();
}

var testList = Foo.myList.ToList(); // get an editable copy
var testList2 = Foo.myList; // get a reference to the immutable static list
ChaseMedallion
  • 20,860
  • 17
  • 88
  • 152
  • Thank you, what would be the difference between `readonly` and `const` here? – Johan Jun 30 '13 at 17:37
  • @Johan in C#, const can only be used with compile-time constants like integers and strings. Readonly just prevents assignment outside of the constructor/static initializer. Check out http://stackoverflow.com/questions/755685/c-static-readonly-vs-const. – ChaseMedallion Jun 30 '13 at 17:43
  • Thanks again for the help, I updated my question if you're intrested in the problem source. – Johan Jun 30 '13 at 18:01