-1

In my Dispose method I am disposing everything a Dataset has as below:

foreach (DataTable myTable in this.Tables)
{
    myTable.Dispose();
}

Here this.Tables is public DataTableCollection Tables { get; }

I am having around 56 tables in this.Tables when it comes near to this call.

It works fine for few tables but suddenly it throws:

System.InvalidOperationException: Collection modified error

I am not sure why is this happening.

I tried to search for this exception a lot but i could not fine why it is breaking in my application.

May be because of threading? or I need to convert it to a list?

Neel
  • 11,625
  • 3
  • 43
  • 61
  • I did not find my answer in that. Please let this thread open – Neel Mar 25 '16 at 07:25
  • 4
    That's simply because you are altering the collection on which you are iterating. So it is not specifically due to dispose, you would get such exception whenever you modify the collection during loop, Remove(), for ex. – Nikhil Vartak Mar 25 '16 at 07:25
  • Yeah i know but what would be workaround for tha @nikhilvartak – Neel Mar 25 '16 at 07:27
  • @CoreDeveloper: accepted answer from the linked question *is* a workaround. Do you need any clarifications about it? – Dennis Mar 25 '16 at 07:29
  • @CoreDeveloper To use `this.Tables.ToList()` etc you will need to have `using System.Linq;` - do you have that? – Matthew Watson Mar 25 '16 at 07:36
  • @CoreDeveloper: this is because `DataTableCollection` implements `IEnumerable`, not `IEnumerable`. You need to call `Cast` first, then `ToList()`. – Dennis Mar 25 '16 at 07:39
  • Yeah I did that. Now no exception. But is it just hack or we literally closed that exception? @Dennis – Neel Mar 25 '16 at 07:42
  • @Dennis, here we are creating another list so that it will not throw exception. agree. but then does it makes sense to dispose another created list? Will it dispose original collection, in short will I get what I wanted to achieve? – Neel Mar 25 '16 at 12:15
  • @CoreDeveloper: you're disposing list *items*, not a list itself (`List` does not implement `IDisposable`, you just can't dispose it). Since `DataTable` is reference type, copying reference from one container (`DataTableCollection`) to another (`List`) doesn't make duplicates - they are the same data tables. Another question is why do you need to dispose data tables at all... – Dennis Mar 25 '16 at 12:52
  • there are almost 57 datatablse. should not I dispose them? @Dennis – Neel Mar 25 '16 at 12:54
  • @CoreDeveloper: `DataTable` inherits disposing logic from base class. This logic just removes "component" from it's "container" (this is about component model). If you're using data tables as in-memory data source, just forget about `Dispose` - GC will do the rest. There are no memory or resource leaks in this case. The truth is that not every `Dispose` *must* be called. – Dennis Mar 25 '16 at 13:28
  • the thing is code is already there which was working fine for almost 10 projects bu in one project its throwing collection modified exception. Can i with what suggested in answer? @Dennis – Neel Mar 28 '16 at 07:17

1 Answers1

4

The exception is because the collection is modified when it's being enumerated. This answer explains well.

The difference is you are enumerating a DataTableCollection, which is not a generic collection so the solution in the linked answer is not suitable in this case. You can cast the collection to a generic one and then enumerate it.

foreach (DataTable thisTable in this.Tables.Cast<DataTable>().ToArray())
Community
  • 1
  • 1
Cheng Chen
  • 42,509
  • 16
  • 113
  • 174
  • That sounds logical :) thanks. Btw one quick question , I just tried it with for loop and it did not throw any exception . Why? – Neel Mar 25 '16 at 07:41
  • @CoreDeveloper If you only enumerate the collection without modification, it's OK. If you delete items in the collection in a for-loop, you will get an exception e.g. accessing `this.Tables[n]` but actually `this.Tables` has less than n items now. – Cheng Chen Mar 25 '16 at 07:45
  • But i was not deleting anything, I mean It was just disposing not removing from list . May be i am misunderstood something – Neel Mar 25 '16 at 07:46
  • @CoreDeveloper Another alternative solution is using a backward for-loop, from n to 0. Disposing item n, item n-1 ... item 0. – Cheng Chen Mar 25 '16 at 07:46
  • Okay got it.. Now I got the workaround but how can I know why it was causing this? I mean I have same dll for more than 10 projects but it fails only for 1 project. – Neel Mar 25 '16 at 07:48
  • @CoreDeveloper Disposing a `DataTable` triggers the remove, not by your code. – Cheng Chen Mar 25 '16 at 07:48
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/107309/discussion-between-danny-chen-and-coredeveloper). – Cheng Chen Mar 25 '16 at 07:49
  • Hi, I was about to mark your answer as complete but only last question, suppose I have used .ToList instead of array, will it dispose "myTable" as it is in code? Inshort it will dispose the things as it was before doing right? Or it will create any other copy and it will dispose that copy. Will it dispose original collection, in short will I get what I wanted to achieve? – Neel Mar 31 '16 at 09:14
  • @CoreDeveloper: `ToList` and `ToArray` have the same result in this case, should work fine. And for other questions, I'm sure that it's caused by somewhere else in your code, because the source code of `DataTable` will not trigger the remove. – Cheng Chen Mar 31 '16 at 09:22
  • no I mean suppose It was disposing before with the code as it is in my question, now after applying your solution it will not throw exception but it will do the task it was doing before right? Like disposing one by one without modifying collection? – Neel Mar 31 '16 at 09:24
  • In short converting it to list will not create duplicates right? – Neel Mar 31 '16 at 09:24
  • @CoreDeveloper: It won't. It creates a new list, whose items are references to the existed `DataTable`s. – Cheng Chen Mar 31 '16 at 09:27
  • In short all the things will be disposed as it was doing before right? – Neel Mar 31 '16 at 09:28
  • because i am going to change in production and any mistake would cause me alot – Neel Mar 31 '16 at 09:28
  • btw you meant it won't for which question? – Neel Mar 31 '16 at 09:29
  • Converting it to list via `ToList` will not create duplicate `DataTable`s. It just create a new list, items in the new list are the original `DataTable`s. – Cheng Chen Mar 31 '16 at 09:31
  • Okay thanks i will commit changes then :) – Neel Mar 31 '16 at 09:33
  • I am still getting this error in production even after converting it to list :( – Neel Apr 07 '16 at 07:17
  • @CoreDeveloper: Can you post a new question, with stack trace and all possible exception information you have, and link to this question? IMO it's not possible that the collection is modified, because you just created it, and it's a local variable, no one can modify it. – Cheng Chen Apr 07 '16 at 07:36