I have been having an issue lately with a Foreach statement and it throwing an Collection was modified; enumeration operation may not execute exception when changing a variable that shouldn't impact the items being enumerated upon, but it still does. Here is my code so I can continue my explanation:
private static CEconTradeOffer RemoveUndesirables(CEconTradeOffer offer)
{
try
{
CEconTradeOffer returned = offer;
foreach (CEconAsset cEconAsset in offer.ItemsToReceive)
{
string marketHashName = cEconAsset.GetMarketHashName(_config.ApiKey);
if (marketHashName.ToLower().Contains("case") ||
marketHashName.Contains("gut") ||
marketHashName.Contains("falchion") ||
marketHashName.Contains("bayonet") ||
marketHashName.Contains("huntsman") ||
marketHashName.Contains("karambit") ||
marketHashName.Contains("butterfly"))
{
//somehow changes both "offer" and "returned" at once.
returned.ItemsToReceive.Remove(cEconAsset);
continue;
}
MarketValue value = MarketHandler.GetPriceOverview(Convert.ToUInt32(cEconAsset.AppId),
marketHashName);
if (!value.Success || int.Parse(value.Volume, NumberStyles.AllowThousands) <= 20)
returned.ItemsToReceive.Remove(cEconAsset);
}
return returned;
}
catch (Exception e)
{
Write.Exception(e);
return null;
}
}
This function was designed to do exactly what it says; remove undesired items from a trade offer. As you can see, I set CEconTradeOffer returned equal to the passed argument of the same type named offer. Strangely enough, whenever I change something inside of returned it causes the foreach statement to break even though I technically shouldn't be impacting offer.ItemsToReceive in any way. returned is what should be modified. When I use the debugger, I notice that BOTH returned and offer get changed at the line returned.ItemsToReceive.Remove(cEconAsset);. Through my previous experience with C# and browsing related problems, this should not be happening since I am creating a new variable that should be separate from offer. I have tried include setting returned equal to a new CEconTradeOffer() and then setting it equal to offer but to no avail. In my research of this problem, I can only seem to find problems where people fail to create a new variable and modifying that in the foreach statement rather than the enumerated value.
Is there something blatantly obvious I am missing? I do not quite understand why I am getting this particular issue when I create a separate variable to change inside the foreach statement.
I am not using more than one thread, so it can't be impacted outside of its own thread of execution.
Thanks in advance.
whenever I change something inside of returned it causes the foreach statement to break even though I technically shouldn't be impacting offer.ItemsToReceive in any way.
It seems that CEconTradeOffer is a reference type, so then you assign
CEconTradeOffer returned = offer;
you get another reference to exactly the same thing.
So when the items are removed using returned.ItemsToReceive.Remove(cEconAsset) they are removed from the same collection, just via another reference.
Related
I'm not really sure if I will be able to explain this behavior but I'll try. I have a program like a dashboard where some graph modules are initialized at startup, each module has a sole purpose to show a graph has a function passed to it which determine the data shown.
The module building (initializing each module type with the corresponding function) is handled in a separate thread using Task. But randomly some of these functions stop working and the List with the data stop being available as if it was never declared.
This is one of the functions, keep in mind it's kind of random which one throws this error, but one of these will always throw an exception. I really can't track down what could cause this behavior I thought about the resources being deleted by other thread but this List is created at startup and only passed and used as a reference. And nowhere in the program I ever reset this list. The same code work in other project and while debugging step by step... I'm really out of tracks to follow
private static IEnumerable<ICompositeValue> GroupEvent(IEnumerable<Event> events, DateTime referenceDate, Month month)
{
List<ICompositeValue> Values= new List<ICompositeValue>();
foreach (Days day in (Giorni[])Enum.GetValues(typeof(Days)))
{
if (day != Giorni.Sunday)
if (events== null) return null; //this was tried to catch the exception
Values.Add(new ICompositeValue()
{
Argument = day.ToString(),
Valore = event.Count(x => (int)x.DDB_APDATA.Value.DayOfWeek == (int)day && (int)x.DDB_APDATA.Value.Month == (int)month && x.DDB_APDATA.Value.Year == referenceDate.Year)
}); ;
}
return valori;
}
As shown in this image Visual Studio can't even evaluate the List value as if it was never declared
Can someone point me in the right direction?
Thanks to everyone!
I just wanted to thank those who tried to help me.
I still didn't get why the debugger acted the way it did since it showed me "x" was null not the inside property, but I managed to track down the problem. I noticed the object mapping from the DataTable was acting strange with the DateTime type variable and indeed something returned null from time to time
As Jeroen Mostert has suggested it seems like some property in your lambda is unexpectedly null. The reason events is not available is because your debugger context is inside the lambda.
x => (int)x.DDB_APDATA.Value.DayOfWeek == (int)day && (int)x.DDB_APDATA.Value.Month == (int)month && x.DDB_APDATA.Value.Year == referenceDate.Year
So one of either x, DDB_APDATA, or Value will likely be null.
Context: C#, WPF, MVVM
In my viewmodels I have been using initialization logic for some of my properties that is basically a check to see if the backing property is null and, if so, initialize it. Finally, return the backing property. Here's an example for list that allows a user to select items to filter by:
List<CBPicklistString> _clientClassificationFilterList;
public List<CBPicklistString> ClientClassificationFilterList
{
get
{
Debug.WriteLine("ClientClassificationFilterList - Get: " + _clientClassificationFilterList?.Count ?? "Null");
if (_clientClassificationFilterList == null)
{
_clientClassificationFilterList = CBPicklists.PicklistStrings(CBPicklists.CLIENT_CLASSIFICATIONS).ToList();
_clientClassificationFilterList.Insert(0, new CBPicklistString() { PicklistStringId = 0, PicklistStringValue = "(All Client Classes)" });
SelectedClientClassificationFilter = _effectiveClientClassificationFilter = _clientClassificationFilterList[0];
OnPropertyChanged("SelectedClientClassificationFilter");
}
return _clientClassificationFilterList;
}
}
My method to apply the filter logic has this code:
if (_effectiveClientClassificationFilter != ClientClassificationFilterList[0])
ActiveClientFilters.Add(new ActiveFilter(_effectiveClientClassificationFilter.PicklistStringValue, "ClientClassification"));
On the initial run, the getter should initialize the list and _effectiveClientClassificationFilter and the if statement should see the comparison as false (objects are equal), meaning that there is no active filter to set. But what I am seeing is that the if statement is behaving as if it sees a true (objects are not equal). When I check the values in the debugger, they are, in fact, equal. It's acting as if there is a concurrency issue where the initialization isn't finishing prior to the comparison. But this isn't a multi-threaded bit of code. Is .Net (or WPF) doing its own thing, here? Is this not a valid way to approach the list initialization? I use this logic paradigm all over the place, (and have been, for years) but this is the first time and the only place I am seeing this funky behavior. There's not a lot of other related code involved.
What am I missing?
I am not sure, but i think the initial value of _effectiveClientClassificationFilter being first in the comparison is used and then the ClientClassificationFilterList is calculated changing the value of _effectiveClientClassificationFilter which i suppose it does not know. So if you reverse the order of condition, it will work correctly.
Instead of
if (_effectiveClientClassificationFilter != ClientClassificationFilterList[0])
use
if (ClientClassificationFilterList[0] != _effectiveClientClassificationFilter)
I know there are lots of ways to do it much better but I've seen it in existing code and now I'm wondering whether or not this could have any negative side effects. Please note the break right after Remove. Therefore I don't care about the iterator in general, however, I do care about unexpected behavior (-> potential exceptions).
foreach (var item in items)
{
//do stuff
if (item.IsSomething)
{
items.Remove(item); //is this safe???
break;
}
}
Could it also be possible the compiler optimizes something in a way I don't expect?
The compiler generates a call to Dispose() on the enumerator that is executed in a finally block, but that shouldn't be a problem. If you break right after removing the item, nothing bad should happen, since you don't use the enumerator anymore.
If you want to do it a different way though (for style reasons or whatever), you could do this:
var item = items.FirstOrDefault(i => i.IsSomething);
if (item != null) {
items.Remove(item);
}
It's also a bit shorter :) (I am assuming here you are using a reference or nullable type in your collection).
The compiler and everything else which is in touch with your application guarantees SC-DRF (sequential consistency for data-race-free programs), so you won't see the difference between the program you wrote and the program which is executed (which is anything but the same). Assuming items is not shared between multiple threads this is completely safe to write and has no unexpected behaviors others than if you would call Remove outside the loop.
You can't change the list while iterating within foreach.
The underlying collection cannot be modified while it's being enumerated. A standard approach is to keep the items to remove in second list , and then after Items has been enumerated, then remove each item from Items.
then u can do this -- its more efficient when dealing with large lists (Assuming entity framework)
var reducedList = items.where(a=>a.IsSomething).toList();
foreach(var item in reducedList)
{
reducedList.Remove(item);
}
this reduces the foreach loop iterations
Suppose I have a method that returns an array or list or some other collection. If something goes wrong inside or when there is simply no data to return, what is better - to return null or to return array (list, etc.) that has length (count) equal to 0?
In fact is it important, or it is just a matter of developer's preferences?
It's better to return an empty collection. This way when someone calls the function like so:
foreach(var i in items)
{
}
it doesn't throw a null reference exception on them.
Technically, you could argue empty vs. null means, but in reality a lot of people (myself included at times) forget to be defensive and don't check to see if the object is null before using it. It's playing into what other people assume is going to happen, which means less bugs and less angry users.
Your iteration code will be a lot easier if you return empty collections instead of null.
However, it may be important to distinguish between an empty collection and no collection of data, so it depends on the semantic of the actual type.
If something "goes wrong" you should throw an exception. If there is no data to return, return an empty collection. Developers generally should not be surprised with a NullReferenceException when they ask for a list of items and there just happen to be none to return.
I could see this going either way. Ultimately an array or collection with have a larger footprint, but is "Safer" in the sense that if the result is being used in future foreach/iterations the result will skip over the code block and not end up with a null object exception.
Well, null and empty have two different meanings. An empty collection effectively means "nothing is here", and could be valid. How would you know if something went wrong based on an empty collection?
While it is safer for the calling method, that doesn't make it better than returning null. Good practice states you should check for null before doing operations on an object. It is cheap anyway.
If something truly went wrong, why cant you throw an exception?
It is developer's preference really.
Returning an empty list
Normally I'd return an empty list so that the receiver of the method's return object doesn't need to check for null and avoid any possible NullReferenceException.
So anyone that expects a list can iterate through the list even though the list is empty (that will be a very quick for-each loop).
Returning null
If you are in an environment where running out of memory is a large issue you could optimize to return null value instead. However that means that everyone that uses the method in question always need to check for null and doesn't solve the problem of possible memory leaks.
If something goes wrong then you shouldn't be returning anything, rather throwing an exception.
You need to agree a consistent approach for the project as to the meaning of NULL and {} and stick to it. Either you are going to use NULL or not, if you are everyone needs to know to check.
I like to think of NULL - not tried to or see if there is anything, there might be some but who knows.
Empty collection - tried to populate and as far as the system is concerned there are no items, which is quite a strong statement.
e.g. Wallet.Notes collection.
NULL - I haven't opened my wallet, so I don't know if I have any notes in it.
List={} - I've checked and I definitely don't have any notes cos I spent it all on beer.
Here is an article by Josh Bloch explaining the same. It's written in Java's context but it should apply to C# equally well.
Return zero-length arrays, not nulls
Although I'd say it's mostly a matter of developer's preference, to return an empty collection might be a better approach.
Let's say you have an object which contains a collection member.
public class Customer {
private IList<Order> _orders;
public Customer() {
_orders = new List<Order>();
}
public IList<Order> Orders {
get {
return _orders;
}
}
}
One generally will prefer to have this member as a readonly property so that its customer's orders don't get lost without any apparent reason. So, returning null is not an option. You would likely work better with an empty collection than a null reference. As such, instantiating the collection within the class constructor is a better approach.
And most importantly, when using DataBinding, for instance, you might get strange behaviour when returning null collection reference, as it will best work with an empty collection instead.
Another example, when iterating through a collection such as:
foreach (Order o in c.Orders) {
// Do something here...
}
This foreach loop will simply not get executed when the collection is empty, without you having to check whether it is a null reference first. It simplifies the code and minimizes its complexity.
This depends on the scenario you're wokring in.
Why is a foreach loop a read only loop? What reasons are there for this?
I'm not sure exactly what you mean by a "readonly loop" but I'm guessing that you want to know why this doesn't compile:
int[] ints = { 1, 2, 3 };
foreach (int x in ints)
{
x = 4;
}
The above code will give the following compile error:
Cannot assign to 'x' because it is a 'foreach iteration variable'
Why is this disallowed? Trying to assigning to it probably wouldn't do what you want - it wouldn't modify the contents of the original collection. This is because the variable x is not a reference to the elements in the list - it is a copy. To avoid people writing buggy code, the compiler disallows this.
I would assume it's how the iterator travels through the list.
Say you have a sorted list:
Alaska
Nebraska
Ohio
In the middle of
foreach(var s in States)
{
}
You do a States.Add("Missouri")
How do you handle that? Do you then jump to Missouri even if you're already past that index.
If, by this, you mean:
Why shouldn't I modify the collection that's being foreach'd over?
There's no surety that the items that you're getting come out in a given order, and that adding an item, or removing an item won't cause the order of items in the collection to change, or even the Enumerator to become invalid.
Imagine if you ran the following code:
var items = GetListOfTOfSomething(); // Returns 10 items
int i = 0;
foreach(vat item in items)
{
i++;
if (i == 5)
{
items.Remove(item);
}
}
As soon as you hit the loop where i is 6 (i.e. after the item is removed) anything could happen. The Enumerator might have been invalidated due to you removing an item, everything might have "shuffled up by one" in the underlying collection causing an item to take the place of the removed one, meaning you "skip" one.
If you meant "why can't I change the value that is provided on each iteration" then, if the collection you're working with contains value types, any changes you make won't be preserved as it's a value you're working with, rather than a reference.
The foreach command uses the IEnumerable interface to loop throught the collection. The interface only defined methods for stepping through a collection and get the current item, there is no methods for updating the collection.
As the interface only defines the minimal methods required to read the collecton in one direction, the interface can be implemented by a wide range of collections.
As you only access a single item at a time, the entire collection doesn't have to exist at the same time. This is for example used by LINQ expressions, where it creates the result on the fly as you read it, instead of first creating the entire result and then let you loop through it.
Not sure what you mean with read-only but I'm guessing that understanding what the foreach loop is under the hood will help. It's syntactic sugar and could also be written something like this:
IEnumerator enumerator = list.GetEnumerator();
while(enumerator.MoveNext())
{
T element = enumerator.Current;
//body goes here
}
If you change the collection (list) it's getting hard to impossible to figure out how to process the iteration.
Assigning to element (in the foreach version) could be viewed as either trying to assign to enumerator.Current which is read only or trying to change the value of the local holding a ref to enumerator.Current in which case you might as well introduce a local yourself because it no longer has anything to do with the enumerated list anymore.
foreach works with everything implementing the IEnumerable interface. In order to avoid synchronization issues, the enumerable shall never be modified while iterating on it.
The problems arise if you add or remove items in another thread while iterating: depending on where you are you might miss an item or apply your code to an extra item. This is detected by the runtime (in some cases or all???) and throws an exception:
System.InvalidOperationException was unhandled
Message="Collection was modified; enumeration operation may not execute."
foreach tries to get next item on each iteration which can cause trouble if you are modifying it from another thread at the same time.