foreach-loop bug in CF2.0?

  • Thread starter Thread starter c_xyTopa
  • Start date Start date
C

c_xyTopa

Hi all,

I get InvalidOperationException while using foreach-loop.
It is not a rule, it just happens in some parts of code, in some - not.
As soon as I replace the foreach-loop by for-loop no Exception is thrown...

What can it be I wonder?

Thanks in advance
 
Well you've given us pretty much no useful information to go on. My guess
is it's a bug in *your* iterator, not the CF.
 
Hello c_xyTopa,
Hi all,

I get InvalidOperationException while using foreach-loop.
It is not a rule, it just happens in some parts of code, in some -
not.
As soon as I replace the foreach-loop by for-loop no Exception is
thrown...
What can it be I wonder?

If you were to post the code inside the loop we might be able to figure it
out...
 
Sorry...
For example here. This is an event-handle of the ui-layer to delete customer.
The _customerManager deletes customer from the list in the data-layer.
The _currentList is the reference to the list of the data-layer.
That means that the _currentList has one element less after that and actualy there is no need for the loop to delete the element for the second time...

List<Customer> _currentList = _customerManager.GetAll();

void view_DeleteCustomer(object sender, CustomerEventArgs e)
{
if (e.Customer == null)
return;
Customer deleted = e.Customer;
deleted.Status = CustomerStatus.Deleted;
_customerManager.Delete(deleted);
// remove from the current list
foreach (Customer c in _currentList)
{
if (c.Guid.CompareTo(deleted.Guid) == 0)
_currentList.Remove(c);
}
view.UpdateCustomerList(_currentList);
}


and a stack... The VS also points on keyword "in" of the loop.

bei System.ThrowHelper.ThrowInvalidOperationException()
at Enumerator.MoveNext()
bei Runtime.HakaMobile.Modules.CustomerModule.CustomersList.CustomerListPresenter.view_DeleteCustomer()
bei Runtime.HakaMobile.Modules.CustomerModule.CustomersList.CustomerListView.DeleteCustomerMenuItem_Click()
bei System.Windows.Forms.MenuItem.OnClick()
bei System.Windows.Forms.Menu.ProcessMnuProc()
bei System.Windows.Forms.Form.WnProc()
bei System.Windows.Forms.Control._InternalWnProc()
bei Microsoft.AGL.Forms.EVL.EnterMainLoop()
bei System.Windows.Forms.Application.Run()
bei Microsoft.Practices.Mobile.CompositeUI.WinForms.FormShellApplication`2.Start()
bei Microsoft.Practices.Mobile.CompositeUI.CabApplication`1.Run()
bei Runtime.HakaMobile.Shell.ShellApplication.Main()
 
Chris was right (suprise), there is a bug in your iterator. You can't
remove items from a list that you're enumerating.

The message of the exception you got should have been:

"Collection was modified; enumeration operation may not execute."

You're code will have to be smarter.
 
Sorry...
For example here. This is an event-handle of the ui-layer to delete customer.
The _customerManager deletes customer from the list in the data-layer.
The _currentList is the reference to the list of the data-layer.
That means that the _currentList has one element less after that and actualy there is no need for the loop to delete the element for the second time...

List<Customer> _currentList = _customerManager.GetAll();

void view_DeleteCustomer(object sender, CustomerEventArgs e)
{
if (e.Customer == null)
return;
Customer deleted = e.Customer;
deleted.Status = CustomerStatus.Deleted;
_customerManager.Delete(deleted);
// remove from the current list
foreach (Customer c in _currentList)
{
if (c.Guid.CompareTo(deleted.Guid) == 0)
_currentList.Remove(c);
}
view.UpdateCustomerList(_currentList);

}

and a stack... The VS also points on keyword "in" of the loop.

bei System.ThrowHelper.ThrowInvalidOperationException()
at Enumerator.MoveNext()
bei Runtime.HakaMobile.Modules.CustomerModule.CustomersList.CustomerListPresenter.view_DeleteCustomer()
bei Runtime.HakaMobile.Modules.CustomerModule.CustomersList.CustomerListView.DeleteCustomerMenuItem_Click()
bei System.Windows.Forms.MenuItem.OnClick()
bei System.Windows.Forms.Menu.ProcessMnuProc()
bei System.Windows.Forms.Form.WnProc()
bei System.Windows.Forms.Control._InternalWnProc()
bei Microsoft.AGL.Forms.EVL.EnterMainLoop()
bei System.Windows.Forms.Application.Run()
bei Microsoft.Practices.Mobile.CompositeUI.WinForms.FormShellApplication`2.Start()
bei Microsoft.Practices.Mobile.CompositeUI.CabApplication`1.Run()
bei Runtime.HakaMobile.Shell.ShellApplication.Main()

You're removing the list element while looping. This can cause this.

- Jin
 
That is no suprise really after looking at your code, as you are iterating
the collection that you are deleting from. So the MoveNext() will be at some
point pointing to an invalid reference and not the reference that you
intended. Basically when you call MoveNext (which is what foreach will do)
this moves a cursor onwards, an index, then when you read the item, calling
IEnumerable.Current the enumerator will check that cursor is not greater than
the list of the collection, if it is, then an InvalidOperationException will
be thrown. Because you are deleting them, this count will not be what it was
when the iterator started. The code will look a little something like this:

object IEnumerator.Current
{
get
{
if ((cursor < 0) || (cursor == mycoll.Length))
throw new InvalidOperationException();
return mycoll[cursor];
}
}

As you can see, your code will break the above.

Copy the items you want to delete into a separate collection maybe a
dictionary, then remove by id or something like that, just don't do it in
your iterator.
 
That is no suprise really after looking at your code, as you are iterating
the collection that you are deleting from. So the MoveNext() will be at some
point pointing to an invalid reference and not the reference that you
intended. Basically when you call MoveNext (which is what foreach will do)
this moves a cursor onwards, an index, then when you read the item, calling
IEnumerable.Current the enumerator will check that cursor is not greater than
the list of the collection, if it is, then an InvalidOperationException will
be thrown. Because you are deleting them, this count will not be what it was
when the iterator started. The code will look a little something like this:

object IEnumerator.Current
{
get
{
if ((cursor < 0) || (cursor == mycoll.Length))
throw new InvalidOperationException();
return mycoll[cursor];
}
}

As you can see, your code will break the above.

Copy the items you want to delete into a separate collection maybe a
dictionary, then remove by id or something like that, just don't do it in
your iterator.
--
Simon Hart
Visual Developer - Device Application Development MVPhttp://simonrhart.blogspot.com

c_xyTopa said:
Sorry...
For example here. This is an event-handle of the ui-layer to delete customer.
The _customerManager deletes customer from the list in the data-layer.
The _currentList is the reference to the list of the data-layer.
That means that the _currentList has one element less after that and actualy there is no need for the loop to delete the element for the second time...
List<Customer> _currentList = _customerManager.GetAll();
void view_DeleteCustomer(object sender, CustomerEventArgs e)
{
if (e.Customer == null)
return;
Customer deleted = e.Customer;
deleted.Status = CustomerStatus.Deleted;
_customerManager.Delete(deleted);
// remove from the current list
foreach (Customer c in _currentList)
{
if (c.Guid.CompareTo(deleted.Guid) == 0)
_currentList.Remove(c);
}
view.UpdateCustomerList(_currentList);
}
and a stack... The VS also points on keyword "in" of the loop.
bei System.ThrowHelper.ThrowInvalidOperationException()
at Enumerator.MoveNext()
bei Runtime.HakaMobile.Modules.CustomerModule.CustomersList.CustomerListPresenter.view_DeleteCustomer()
bei Runtime.HakaMobile.Modules.CustomerModule.CustomersList.CustomerListView.DeleteCustomerMenuItem_Click()
bei System.Windows.Forms.MenuItem.OnClick()
bei System.Windows.Forms.Menu.ProcessMnuProc()
bei System.Windows.Forms.Form.WnProc()
bei System.Windows.Forms.Control._InternalWnProc()
bei Microsoft.AGL.Forms.EVL.EnterMainLoop()
bei System.Windows.Forms.Application.Run()
bei Microsoft.Practices.Mobile.CompositeUI.WinForms.FormShellApplication`2.Start()
bei Microsoft.Practices.Mobile.CompositeUI.CabApplication`1.Run()
bei Runtime.HakaMobile.Shell.ShellApplication.Main()

Another way to remove items from the list you're iteration through is
to index through them in reverse using the for-statement. Since the
iteration is heading towards index of zero (0), removing the current
index item is safe.

- Jin
 
Sure you could do that but you couldn't use the foreach keyword, instead the
for. For example:
Something like the following should work.

for (int i = mylist.Count -1; i > -1; i--)
{
Customer mycust = mylist;
//condition...
mylist.Remove(mycust);
}

--
Simon Hart
Visual Developer - Device Application Development MVP
http://simonrhart.blogspot.com


Jin Chang said:
That is no suprise really after looking at your code, as you are iterating
the collection that you are deleting from. So the MoveNext() will be at some
point pointing to an invalid reference and not the reference that you
intended. Basically when you call MoveNext (which is what foreach will do)
this moves a cursor onwards, an index, then when you read the item, calling
IEnumerable.Current the enumerator will check that cursor is not greater than
the list of the collection, if it is, then an InvalidOperationException will
be thrown. Because you are deleting them, this count will not be what it was
when the iterator started. The code will look a little something like this:

object IEnumerator.Current
{
get
{
if ((cursor < 0) || (cursor == mycoll.Length))
throw new InvalidOperationException();
return mycoll[cursor];
}
}

As you can see, your code will break the above.

Copy the items you want to delete into a separate collection maybe a
dictionary, then remove by id or something like that, just don't do it in
your iterator.
--
Simon Hart
Visual Developer - Device Application Development MVPhttp://simonrhart.blogspot.com

c_xyTopa said:
Sorry...
For example here. This is an event-handle of the ui-layer to delete customer.
The _customerManager deletes customer from the list in the data-layer.
The _currentList is the reference to the list of the data-layer.
That means that the _currentList has one element less after that and actualy there is no need for the loop to delete the element for the second time...
List<Customer> _currentList = _customerManager.GetAll();
void view_DeleteCustomer(object sender, CustomerEventArgs e)
{
if (e.Customer == null)
return;
Customer deleted = e.Customer;
deleted.Status = CustomerStatus.Deleted;
_customerManager.Delete(deleted);
// remove from the current list
foreach (Customer c in _currentList)
{
if (c.Guid.CompareTo(deleted.Guid) == 0)
_currentList.Remove(c);
}
view.UpdateCustomerList(_currentList);
}
and a stack... The VS also points on keyword "in" of the loop.
bei System.ThrowHelper.ThrowInvalidOperationException()
at Enumerator.MoveNext()
bei Runtime.HakaMobile.Modules.CustomerModule.CustomersList.CustomerListPresenter.view_DeleteCustomer()
bei Runtime.HakaMobile.Modules.CustomerModule.CustomersList.CustomerListView.DeleteCustomerMenuItem_Click()
bei System.Windows.Forms.MenuItem.OnClick()
bei System.Windows.Forms.Menu.ProcessMnuProc()
bei System.Windows.Forms.Form.WnProc()
bei System.Windows.Forms.Control._InternalWnProc()
bei Microsoft.AGL.Forms.EVL.EnterMainLoop()
bei System.Windows.Forms.Application.Run()
bei Microsoft.Practices.Mobile.CompositeUI.WinForms.FormShellApplication`2.Start()
bei Microsoft.Practices.Mobile.CompositeUI.CabApplication`1.Run()
bei Runtime.HakaMobile.Shell.ShellApplication.Main()
"<ctacke/>" <ctacke[at]opennetcf[dot]com> schrieb im NewsbeitragWell you've given us pretty much no useful information to go on. My guess
is it's a bug in *your* iterator, not the CF.

Chris Tacke, eMVP
Join the Embedded Developer Community
http://community.opennetcf.com
I get InvalidOperationException while using foreach-loop.
It is not a rule, it just happens in some parts of code, in some - not.
As soon as I replace the foreach-loop by for-loop no Exception is
thrown...
What can it be I wonder?
Thanks in advance

Another way to remove items from the list you're iteration through is
to index through them in reverse using the for-statement. Since the
iteration is heading towards index of zero (0), removing the current
index item is safe.

- Jin
 
Sure you could do that but you couldn't use the foreach keyword, instead the
for. For example:
Something like the following should work.

 for (int i = mylist.Count -1; i > -1; i--)
 {
      Customer mycust = mylist;
     //condition...
     mylist.Remove(mycust);
 }

--
Simon Hart
Visual Developer - Device Application Development MVPhttp://simonrhart.blogspot.com



Jin Chang said:
That is no suprise really after looking at your code, as you are iterating
the collection that you are deleting from. So the MoveNext() will be at some
point pointing to an invalid reference and not the reference that you
intended. Basically when you call MoveNext (which is what foreach willdo)
this moves a cursor onwards, an index, then when you read the item, calling
IEnumerable.Current the enumerator will check that cursor is not greater than
the list of the collection, if it is, then an InvalidOperationException will
be thrown. Because you are deleting them, this count will not be what it was
when the iterator started. The code will look a little something like this:
        object IEnumerator.Current
        {
            get
            {
                if ((cursor < 0) || (cursor == mycoll.Length))
                    throw new InvalidOperationException();
                return mycoll[cursor];
            }
        }
As you can see, your code will break the above.
Copy the items you want to delete into a separate collection maybe a
dictionary, then remove by id or something like that, just don't do itin
your iterator.
--
Simon Hart
Visual Developer - Device Application Development MVPhttp://simonrhart..blogspot.com
:
Sorry...
For example here. This is an event-handle of the ui-layer to delete customer.
The _customerManager deletes customer from the list in the data-layer.
The _currentList is the reference to the list of the data-layer.
That means that the _currentList has one element less after that andactualy there is no need for the loop to delete the element for the second time...
List<Customer> _currentList = _customerManager.GetAll();
void view_DeleteCustomer(object sender, CustomerEventArgs e)
{
    if (e.Customer == null)
        return;
    Customer deleted = e.Customer;
    deleted.Status = CustomerStatus.Deleted;
    _customerManager.Delete(deleted);
    // remove from the current list
    foreach (Customer c in _currentList)
    {
        if (c.Guid.CompareTo(deleted.Guid) == 0)
            _currentList.Remove(c);
    }
    view.UpdateCustomerList(_currentList);
}
and a stack... The VS also points on keyword "in" of the loop.
bei System.ThrowHelper.ThrowInvalidOperationException()
at Enumerator.MoveNext()
bei Runtime.HakaMobile.Modules.CustomerModule.CustomersList.CustomerListPresent­er.view_DeleteCustomer()
bei Runtime.HakaMobile.Modules.CustomerModule.CustomersList.CustomerListView.De­leteCustomerMenuItem_Click()
bei System.Windows.Forms.MenuItem.OnClick()
bei System.Windows.Forms.Menu.ProcessMnuProc()
bei System.Windows.Forms.Form.WnProc()
bei System.Windows.Forms.Control._InternalWnProc()
bei Microsoft.AGL.Forms.EVL.EnterMainLoop()
bei System.Windows.Forms.Application.Run()
bei Microsoft.Practices.Mobile.CompositeUI.WinForms.FormShellApplication`2.Star­t()
bei Microsoft.Practices.Mobile.CompositeUI.CabApplication`1.Run()
bei Runtime.HakaMobile.Shell.ShellApplication.Main()
"<ctacke/>" <ctacke[at]opennetcf[dot]com> schrieb im NewsbeitragWell you've given us pretty much no useful information to go on.  My guess
is it's a bug in *your* iterator, not the CF.
--
Chris Tacke, eMVP
Join the Embedded Developer Community
http://community.opennetcf.com
Hi all,
I get InvalidOperationException while using foreach-loop.
It is not a rule, it just happens in some parts of code, in some - not.
As soon as I replace the foreach-loop by for-loop no Exception is
thrown...
What can it be I wonder?
Thanks in advance
Another way to remove items from the list you're iteration through is
to index through them in reverse using the for-statement.  Since the
iteration is heading towards index of zero (0), removing the current
index item is safe.
- Jin- Hide quoted text -

- Show quoted text -


A way to do it without implicit looping would be to use the RemoveAll
method by creating a Predicate<Customer>. Its a cool trick that might
not be right for your solution but I thought I would post it since
there a lot of people that don't know anything about anonymous
delegates. I'm not sure of the performance impact, and if this method
is really bad I hope somebody would let me know ;)

//Your remove code would change to the following.
int numberRemoved = _currentList.RemoveAll( c.GeneratePredicate() );

//You would need to add a GeneratePredicate method, probably at the
class level to make it easier on yourself in case you needed to change
the comparison.
public Predicate<Customer> GeneratePredicate()
{
return delegate( Customer c )
{
return _guid == c.Guid;
};
}
 
Back
Top