• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 689
  • Last Modified:

LINQ anonymous types and reference issues

Hi experts, I'm fairly new to the whole linq stuff. Today I came across a behaviour I don't really understand.
Frist, see code below, it's an extension method for a dataset.
This one works, no problem.

but, if I don't loop through TableNamesToDelete.ToList() and would instead use TableNamesToDelete directly, I get an exception in the foreach loop, saying the enumeration has been changed while looping.
the same happens when I create an anonymous type in the linq query, like
select new{t.TableName} and use TableNamesToDelete directly.
So, somehow it seems I still have a reference to the datatables in the datasets, which causes the foreach-loop to fail.

I don't really get it, why is there still a reference when I create an anonymous type?
Or am I getting something wrong here?
public static class ExtensionMethods
    {
        public static void RemoveUnnecessaryTables(this DataSet ds)
        {
            var TableNamesToDelete = from t in ds.Tables.Cast<DataTable>()
                                     where t is INoImport
                                     select t.TableName;


            foreach(string TName in TableNamesToDelete.ToList())
            {
                if(ds.Tables.Contains(TName))
                    ds.Tables.Remove(TName);
            }
        }

    }

Open in new window

0
Arikael
Asked:
Arikael
  • 3
  • 3
2 Solutions
 
sanket_1985Commented:
The reason being that you have called Remove method on DataSet and that modifies the enumerated values. This change triggers Exception.

When you use ToList() method, it inherits properties and methods of List class that allows you to delete entries, which is not the case in LINQ Expressions.
0
 
ArikaelAuthor Commented:
so, you say, even when I return an anonymous type in my linq-query, I have somehow a reference to the datatable/dataset?
0
 
käµfm³d 👽Commented:
Use a "for" loop instead and work backwards (see below). As sanket_1985 stated, you cannot modify a collection that you are iterating over--it would screw up the internal iterator for the collection. Use a "for" loop when you want to add/remove from a collection in a loop.
var TableNamesToDelete = (from t in ds.Tables.Cast<DataTable>()
                          where t is INoImport
                          select t.TableName).ToList();

for(int i = TableNamesToDelete.Count - 1; i >= 0; i--)
{
    if(ds.Tables.Contains(TableNamesToDelete[i]))
        ds.Tables.Remove(TableNamesToDelete[i]);
}

Open in new window

0
Never miss a deadline with monday.com

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

 
käµfm³d 👽Commented:
In hindsight, you don't have to "work backwards" in this particular scenario. You would be fine to start at the beginning of TableNamesToDelete and go forward.
0
 
ArikaelAuthor Commented:
Hi,

I know that I can't modify a collection I'm iterating over :)
But I don't really understand why TableNamesToDelete seems to have a reference to to the dataset/datatable, even when I return a new anonymous type.
0
 
käµfm³d 👽Commented:
I misunderstood your question  = )


I can't explain the intricate details of this, but if you look at "TableNamesToDelete" in debug mode, it's not an Enumerable<string>; rather it is a WhereSelectEnumerableIterator<DataTable, string>. I believe this is where your reference is being held.
0
 
ArikaelAuthor Commented:
thanks

I still find it strange, especially when I return an anonymous type. It's not the behaviour I would expect.
0

Featured Post

Receive 1:1 tech help

Solve your biggest tech problems alongside global tech experts with 1:1 help.

  • 3
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now