none
“Collection was modified; enumeration operation might not execute” inside System.Data.TypedTableBase<> RRS feed

  • Question

  • I have an .NET 4.0 assembly; it is registered in GAC and works as part of a BizTalk “orchestration”. 
    Sometimes I get the following error  - “Collection was modified; enumeration operation might not execute. : System.InvalidOperationException: Collection was modified; enumeration operation might not execute.”. I cannot reproduce it; when I run the same processing of the same data, my assembly does not generate the error in this place.

    The error happens when I call ‘.Where(<condition>).ToArray()’ for a datatable object: an object of classd System.Data.TypedTableBase<MyDataRowClass>.

    Here is the code:

    int? setTypeGroupId;
    ...
    
    return instances.WorkContributors.Where
    	(
    		c =>
    			!c.IsInterestedPartyNoNull()
    			&& c.InterestedPartyNo == publisherIpNo
    			&& c.SetTypeNo == 1
    			&& (c.RecordType == "SPU")
                && c.TypeCode == "E" 
                && (!setTypeGroupId.HasValue ||  
                    (setTypeGroupId.HasValue && c.SetTypeGroupID == setTypeGroupId))
    	)
    	.ToArray();



    The object ‘instances’ is a dataset – my class produced from System.Data.DataSet.
    The property ‘instances.WorkContributors’ is a datatable: an object of class System.Data.TypedTableBase<MyDataRowClass>.
    The class MyDataRowClass  is produced from System.Data.DataRow.

    The call stack after the error was the following:

    Collection was modified; enumeration operation might not execute. : System.InvalidOperationException: Collection was modified; enumeration operation might not execute.
         at System.Data.RBTree`1.RBTreeEnumerator.MoveNext()
         at System.Linq.Enumerable.<CastIterator>d__97`1.MoveNext()
         at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
         at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
         at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
         at MyProduct.FileParser.Types.CWR.PWRType.GetPublishers(CWRWorkInstances instances, Nullable`1 setTypeGroupId)
         at MyProduct.FileParser.Validation.Concreate.PwrTypeValidation.ValidatePublisherNumber()
         at MyProduct.FileParser.Validation.Concreate.PwrTypeValidation.Validate()
         at MyProduct.FileParser.Types.CWR.PWRType.StoreRecord(CWRWorkInstances workInstances, CWRWorkParsingContext context)
         at MyProduct.FileParser.Groups.CWR.NWRGroup.StoreGroup(Int32 workBatchID, CWRFileCommonData commonData)
         at MyProduct.FileParser.CWRParser.ProcessCWRFile(String fileName, Boolean wait, Boolean deleteFile, String sourceFileName)


    I cannot understand why the error happens; and why it happens only sometimes and does not happen on the same processed data again.
    The error “Collection was modified; enumeration operation might not execute.” Itself is pretty straightforward for me; but I do not see why it happens in that my code.  The error is excepted if a code like this:

    foreach (DataRow currRow in _someDataTable.Rows)
    {
        if (/*deletion condition*/)
        {
            someDataTable.Rows.Remove(currRow);
        }
    }



    But my code above just wants to enumerate System.Data.TypedTableBase<MyDataRowClass> and convert the result into an array. 

    Any ideas?

    Tuesday, April 9, 2019 3:40 PM

All replies

  • Try protect all access to instances.WorkContributors with lock block, so other thread will not be able to add/remove elements before your iteration is completed.

    Wednesday, April 10, 2019 2:34 AM
    Answerer
  • Thanks for the answer.
    Yes, I see  your idea – you think the problem is caused by some other thread that modifies  instances.WorkContributors at the very same time the first thread calls “instances.WorkContributors.Where…”

    I have looked through my code; and still seen no ability – how it is possible. Yes – my DLL may be called by BizTalk from many threads at the same time. But I do not see how a thread can reach the instances.WorkContributors of another thread. The object ‘instances’ is created as a local variable in a function:


    var instances = new MyCLass();


    Well, maybe I still do not understand something – I am not an experienced .NET developer.
    I will keep reviewing my sources to find out – how “some other thread may modify instances.WorkContributors”.
    Maybe you can give me a hint in this direction?

    Wednesday, April 10, 2019 9:07 AM
  • I would use "WorkContributors" as keyword and do global search on the solution to identify which parts are using it, then determine the nature (whether it's read-only, or will add/remove elements) and do protection appropiately.

    If you find some places where you set WorkContributors to data binding controls, you may want to switch to buffered approach where the data binding controls bind to a copy of WorkContributors instead, and you apply changes on "save" kind of actions when Rows.RowState != DataRowState.Unchanged.

    Thursday, April 11, 2019 1:22 AM
    Answerer