Home > database >  Is it possible to alter an entry in an un-indexable collection?
Is it possible to alter an entry in an un-indexable collection?

Time:09-22

This is more or less a theoretical question, based on some hands-on experience:

In my application, I have quite some threads and my colleagues have the habit of disposing of those threads, one by one, and putting the value null in them.

I though this was a bad idea, so I created a List of those threads, and tried to do the whole thing in a loop, something like:

private List<SomeThread> _SomeThreads = new List<SomeThread>();
...
foreach (SomeThread l_SomeThread in _SomeThreads)
{
    if (l_SomeThread != null)
    {
        l_SomeThread.Dispose();
        l_SomeThread = null;
    }
}

That went sour, because of the compiler error "cannot assign to 'l_SomeThread' because it is a 'foreach iteration variable'".
"No problem", I thought, I can just use a counter for looping through the List.

For verification, I have created this simple piece of source code, and indeed, I had the same compiler error:

List<int> test = new List<int>();
test.Add(1);  test.Add(3); test.Add(5);

foreach (int i in test)
{
  i = 2*i;
}

Until here, everything is clear, as I can replace the last source by:

for (int i=0; i<test.Count(), i  )
{
  i = 2 * i;
}

But now I wonder: what about non-indexable collections, which you can only run through, using a foreach loop? Does this automatically mean that their elements cannot be altered?
Or do such collections not exist in C#, exactly for that reason? (I had a look at the C# Collections explanation and I didn't find any of them which look not "indexable")

CodePudding user response:

foreach uses the IEnumerable<T> interface, and do not allow reassignment of the loop variable, since that most likely is a logical bug.

What you should do it use a for-loop:

for(int i = 0; i < _SomeThreads.Count; i  ){
    if (_SomeThreads[i] != null){
        _SomeThreads[i].Dispose();
        _SomeThreads[i] = null;
    }
}

Other collections like ICollection/ReadOnlyList/IEnumerable cannot have values reassigned, but you could still dispose the elements, and dispose should be idempotent. It also does not make much sense to keep a bunch of null values in the list, just remove them instead. If yo do elect to remove them you should probably iterate over the collection in the reverse order.

In my application, I have quite some threads and my colleagues have the habit of disposing of those threads, one by one, and putting the value null in them.

To me this but does not make to much sense, but it sounds super scary:

  1. Thread is not disposable
  2. You should probably be using tasks instead of threads.
  3. If 'Dispose' means Thread.Abort(), you have some serious issues
  4. Multi threaded programming is difficult. You need to be careful and know what you are doing to avoid potential bugs, and such bugs are often notoriously difficult to debug.

So I would take a step back to see what you are actually doing, and doing some reading on best practices for multi threaded programming.

CodePudding user response:

My Answer is pretty much same as @JonasH.

It is actually not problem with list rather foreach loop. If you can have a look at the foreach specification/explanation here:

  1. Forach specification explantion
  2. See this explanation: https://stackoverflow.com/a/7838178/1349365

So, to answer your question, you can change/modify any item in a List but not with foreach.

Look at this example https://dotnetfiddle.net/ap67pg, list is basically a dynamic array.

  • Related