I am populating a List A-Sync and I want to show the last 20 objects in a console. This is causing me a huge pain in the ass because I'm getting exceptions like: "Collection was modified after the enumerator was instantiated." and "Collection was modified after the enumerator was instantiated."
Right now this is what I'm trying (note that this is pseudo code):
Initiate the a-sync task which will fill the list
stopWatch.Start();
program.doAsynctask(InputList, ref OutputList, sniffNotify);
while (program.busy)
{
print();
Thread.Sleep(200);
}
stopWatch.Stop();
Console.Clear();
Console.WriteLine("Task done!");
The method that does the task initiation
public void doAsynctask(List<Input> InputList, ref List<Result> OutputList, Action<Result> callback)
{
if (busy)
return;
if (Input== null || Input.Count() == 0)
{
return;
}
busy = true;
taskCount = Input.Count();
this.InputList = InputList;
this.OutputList = OutputList;
//initiate
Task.Run(() => innerAsyncTask(callback));
}
The method that does the task
private void innerAsyncTask(Action<Result> callback)
{
foreach (Input inputObject in InputList)
{
currentInputObject = inputObject;
Result result = new Result();
result = doWebRequestOrsomethingThatTakesTime(inputObject);
Thread.Sleep(250); //simulate some latency
OutputList.Add(result);
//notify
callback(result);
currentTask++;
}
busy = false;
}
This method is called by the callback
public void sniffNotify(Result sr)
{
printQueue.Add(sr); //printQueue is a queue that can only contain 20 items
}
This is the print function where I get the exception (I tried to use a lock but is does not help)
public void print()
{
TimeSpan ts = stopWatch.Elapsed;
string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
ts.Hours, ts.Minutes, ts.Seconds,
ts.Milliseconds / 10);
Console.Clear();
Console.WriteLine("Running program");
Console.WriteLine("");
Console.WriteLine("Time elapsed: "+ elapsedTime);
Console.WriteLine(String.Format("{0} of the {1} tasks are done", program.currentTask, program.taskCount));
Console.WriteLine((program.busy ? String.Format("Bussy with {0}", program.currentInputObject) : "All done"));
Console.WriteLine("");
Console.WriteLine("");
lock (printQueue) {
foreach (Result res in printQueue) { //Getting "Collection was modified after the enumerator was instantiated." exception here
Console.WriteLine(String.Format("Done result {0}: \t\t {1}", res.id, res.value));
}
}
}
This is the printQueue Class
class FixedSizeList<T> : IEnumerable where T : new()
{
public int size { get; set; }
private Queue<T> items = new Queue<T>();
public int Count { get{ return items.Count(); } }
public FixedSizeList(int size)
{
this.size = size;
for (int a = 0; a < size; a++)
{
items.Enqueue(new T());
}
}
public void Add(T item)
{
items.Enqueue(item);
if (items.Count >= size)
{
items.Dequeue();
}
}
public IEnumerator<T> GetEnumerator()
{
return items.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
internal List<T> ToList()
{
return items.ToList();
}
}
Now I have the idea that I am completely doing this the wrong way. How can I achieve what I want?