.NET Exception Handling – System.InvalidOperationException

Moving right along through the magical world of our .NET Exception Handling series, today we’re going to cover the System.InvalidOperationException. The System.InvalidOperationException is a fairly common exception, as it is typically thrown when there’s a failed attempt to invoke a method, caused by something other than invalid arguments passed to that method.

In this article, we’ll examine where System.InvalidOperationException sits within the .NET exception hierarchy, look at why System.InvalidOperationExceptions typically appear, and see how to deal with them should you encounter one yourself. Let’s get this party started!

The Technical Rundown

When Should You Use It?

Unlike many exceptions in .NET, you may have noticed that System.InvalidOperationException resides quite close to the top of the exception hierarchy, as a direct descendent of System.SystemException. This typically indicates a .NET exception that is very common, or is applicable in many scenarios, and System.InvalidOperationException(arguably) falls into both camps.

The challenge with describing the System.InvalidOperationException is that it can occur in a wide variety of scenarios. As mentioned in the introduction, a System.InvalidOperationException is thrown when a method invocation fails for a reason other than invalid arguments. The official documentation gives a few potential examples of what might cause this, including:

  • When an IEnumerator.MoveNext call is made on a collection that has since been modified after the enumerator was generated (more on this one later).
  • Calling ResourceSet.GetString if the resource was already closed prior to this call.
  • Modifying XML via the XContainer.Add method, if doing so would generate invalid XML.
  • Attempting to modify the UI from a secondary thread that is not the main/UI thread.

This is by no means an exhaustive list, so it’s impossible to cover all potential scenarios that a System.InvalidOperationException could occur. Instead, to continue our examination, we’ll just take a look at one particular means by which a System.InvalidOperationException is typically raised: Modifying a collection after the enumeration of that collection has been generated, then continuing to utilize the enumeration.

To illustrate this in action, we’ve got our full code example below:

We won’t get into detail about the Utility namespace, but instead we’ll look at the Airbrake.InvalidOperationException namespace, where our problematic code resides. In this somewhat realistic example, we’ve got an interface called IBook, which specifies a few fields (Author and Title) for our Bookclass:

Now, using our Book class, our InvalidExample method generates a List<Book> collection called books, and adds a few of my favorites selections to the list. From there, we confirm that our collection contains the five Books we added, then we generate our Enumerator using the foreach loop block. Inside our loop, we output the current bookinstance, then create a newBook of Robinson Crusoe. We then call books.Add to add our newBook to the collection, and continue the loop using our previously established enumeration:

The trouble is, our enumeration was established back when we had only five books, but before our second call to foreach, we’ve modified the collection and added a sixth book. Sure enough, this throws a System.InvalidOperationException:

If adding new items to the collection during the enumeration is a necessity, the best way to do it is to generate a static enumeration beforehand; one that doesn’t directly access the modified collection each loop. For example, using for, instead of foreach, allows us to reference pre-determined indexes of the collection items, rather than direct collection items during the loop. Here is our slightly modified code to illustrate a successful fix:

The key is to detach enumeration from the collection that is changing. We’ve initially stated that our enumerator will only loop through a total of the first five items (indexes), regardless of what is added to the collection afterward. This produces an expected result without a System.InvalidOperationException:

To get the most out of your own applications and to fully manage any and all .NET Exceptions, check out the Airbrake .NET Bug Handler, offering real-time alerts and instantaneous insight into what went wrong with your .NET code, along with built-in support for a variety of popular development integrations including: JIRA, GitHub, Bitbucket, and much more.