Created
May 16, 2014 20:22
-
-
Save theredpea/7dc62e93d641226e91ce to your computer and use it in GitHub Desktop.
ModifyingWhileIterating
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//I couldn't figure out why I modified a List but later in the code the List seemed unchanged. | |
//I was modifying something returned the public accessor { get }; | |
//But wasn't truly changing the private variable behind the public variable | |
//Again I ran into it while trying to fix TT0263356 | |
void Main() | |
{ | |
List<List<Ref>> Refss = new List<List<Ref>>{ | |
new List<Ref> { | |
new Ref() | |
} | |
}; | |
foreach(List<Ref> Refs in Refss) | |
{ | |
foreach(Ref r in Refs) | |
{ | |
r.startString="modified List<List<Ref>>"; | |
} | |
} | |
Console.WriteLine(Refss[0][0].startString); | |
ListRef lr = new ListRef(){ Refs = new List<Ref> { new Ref() } }; | |
foreach(Ref r in lr.Refs) | |
{ | |
//ModifyRef(r); | |
r.startString="modified ListRef()'s Refs (a List<Ref>)"; | |
} | |
Console.WriteLine(lr.Refs[0].startString); | |
ListRefImplicitSetter lris = new ListRefImplicitSetter(); | |
foreach(Ref r in lris.Refs) | |
{ | |
//ModifyRef(r); | |
r.startString="modified ListRefImplicitSetter()'s Refs (a List<Ref>)"; | |
} | |
Console.WriteLine(lris.Refs[0].startString); | |
ListRefNoSetter lrns = new ListRefNoSetter(){ Refs = new List<Ref> { new Ref() } }; | |
foreach(Ref r in lrns.Refs) | |
{ | |
//ModifyRef(r); | |
r.startString="modified ListRefNoSetter()'s Refs (a List<Ref>)"; | |
} | |
Console.WriteLine(lrns.Refs[0].startString); | |
} | |
public void ModifyRef(Ref r) | |
{ | |
r.startString="modified"; | |
} | |
public class ListRefImplicitSetter | |
{ | |
public List<Ref> Refs { get { return new List<Ref> { new Ref() }; } } | |
} | |
public class ListRefNoSetter | |
{ | |
public List<Ref> Refs { get; set;} | |
} | |
public class ListRef | |
{ | |
public List<Ref> Refs { | |
get { return _Refs; } | |
set { _Refs = value; } | |
} | |
private List<Ref> _Refs; | |
} | |
public class Ref | |
{ | |
public int startInt; | |
public string startString; | |
public Ref() | |
{ | |
startInt=1; | |
startString="start - this has not been modified"; | |
} | |
} | |
// Define other methods and classes here | |
/*BEFORE: | |
NOTE: _ExpirableItems is always null; and Data didn't change, so it always returned Data! | |
public List<T> ExpirableItems | |
{ | |
get { return _ExpirableItems ?? Data.Deserialize<List<T>>() ?? new List<T>(); } | |
set { _ExpirableItems = value; } | |
} | |
private List<T> _ExpirableItems; | |
AFTER: | |
public List<T> ExpirableItems | |
{ | |
get { | |
if(null==_ExpirableItems){ | |
_ExpirableItems = Data.Deserialize<List<T>>() ?? new List<T>(); | |
} | |
return _ExpirableItems; | |
} | |
set { _ExpirableItems = value; } | |
} | |
private List<T> _ExpirableItems; | |
*/ | |
/* BEFORE: | |
IEnumerable<T> removedItems = ExpirableItems.Where(i => i.IsExpired); | |
//This actually removes them; | |
int num = ExpirableItems.RemoveAll(i => i.IsExpired); | |
return removedItems; | |
Note that ExpirableItems.Where is deferred; | |
But RemoveAll() is not deferred, and modifies the item in place; | |
I wanted to do both; remove the items and get the items that were removed; | |
Probably better to do an approach like this: http://stackoverflow.com/questions/419019/split-list-into-sublists-with-linq | |
A nice test would be Trace.AssertIs | |
AFTER: | |
IEnumerable<T> removedItems = ExpirableItems.Where(i => i.IsExpired).ToList(); | |
//This actually removes them; | |
int num = ExpirableItems.RemoveAll(i => i.IsExpired); | |
return removedItems; | |
Or I could force execution with ToList(); | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment