Skip to content

Contact sales

By filling out this form and clicking submit, you acknowledge our privacy policy.

Commonly Encountered Exceptions- InvalidOperationException

Common causes of an InvalidOperationException include updating a UI thread from a non-UI thread, changing a collection while iterating it, and more.

Nov 9, 2018 • 8 Minute Read

Introduction

An exception is a runtime error in a program that violates a system or application constraint, or a condition that is not expected to occur during normal execution of the program. Possible causes of exceptions include attempting to connect to a database that no longer exists, when a program tries to divide a number by zero, or opening a corrupted XML file. When these occur, the system catches the error and raises an exception. Catching exceptions is a way of handling these unexpected errors by defining a block of code that will be run when an exception is thrown.

There are a few commonly encountered exception types that are useful to be aware of. In this guide, we will look at the InvalidOperationException exception type.

Encountering the InvalidOperationException Exception Type

The InvalidOperationException exception type is thrown when a method call is invalid for the object's current state. Some common causes of the InvalidOperationException exception are:

  1. Updating a UI thread from a non-UI thread.
  2. Changing a collection while iterating it.
  3. Sorting an array or collection whose objects cannot be compared.
  4. Casting a Nullable that is null to its underlying type.
  5. Calling a System.Linq.Enumerable method on an empty collection.

Let's look at an example where we add items to a collection while iterating it. Create a new console application project. Open Program.cs and put the following code in it:

      using System;
using System.Collections.Generic;

namespace MyApp
{
  class Program
  {
    static void Main(string[] args)
    {
      try
      {
        var accounts = new List<Account>() {
          new Account("Jimmy Gradle", 900),
          new Account("Sophie Gradle", 300)
        };

        Console.WriteLine("Looping through available accounts");

        foreach (Account account in accounts)
        {
          Console.WriteLine("{0} has {1} dollars", account.Name, account.Balance);
          if (account.Name == "Sophie Gradle")
          {
            var newAccount = new Account("Jeremy brown", 1500);
            Console.WriteLine("Adding {0} to the collection...\n", newAccount.Name);
            accounts.Add(newAccount);
          }
        }
      }
      catch (InvalidOperationException ex)
      {
        Console.WriteLine("Oh no, Something went wrong");
        Console.WriteLine(ex.Message);
      }
    }

    class Account
    {
      public Account(string name, int balance)
      {
        Name = name;
        Balance = balance;
      }

      public string Name { get; private set; }
      public int Balance { get; private set; }
    }
  }
}
    

From the code above, we defined an Account class. In the Main method we have a collection of Account type and, while looping through it, we print the current account details to the console, then add a new Account object to the collection. If we run the program as it is, we will get the following result.

      Looping through available accounts
Jimmy Gradle has 900 dollars
Sophie Gradle has 300 dollars
Adding Jeremy brown to the collection...

Oh no, something went wrong
Collection was modified; enumeration operation may not execute.
    

We encountered an error at the point of adding a new item to the collection inside the foreach statement. This is because the foreach statement, which is used to iterate members of a collection, only allows you to read or modify the individual items and not to add or remove items from the collection. To fix the error we are getting, because we can't add an item to a collection while iterating it, we will use the for statement and iterate by its index.

Update the code within the try block with the following:

      var accounts = new List<Account>() {
  new Account("Jimmy Gradle", 900),
  new Account("Sophie Gradle", 300)
};
Console.WriteLine("Looping through available accounts");

int count = accounts.Count - 1;
for (int index = 0; index <= count; index++)
{
  var account = accounts[index];
  Console.WriteLine("{0} has {1} dollars", account.Name, account.Balance);
  if (account.Name == "Sophie Gradle")
  {
    var newAccount = new Account("Jeremy brown", 1500);
    Console.WriteLine("Adding {0} to the collection… \n", newAccount.Name);
    accounts.Add(newAccount);
  }
}
    

The fix was to detach the enumeration from the collection that is changing. We got the count of items in the collection and used it to create the for loop statement. When you run the application, it should run without any error and output the following to the console:

      Looping through available accounts
Jimmy Gradle has 900 dollars
Sophie Gradle has 300 dollars
Adding Jeremy brown to the collection...
    

Throwing the InvalidOperationException Exception Type

In the previous section, we saw that the InvalidOperationException exception type is thrown when a method call is invalid for the object's current state. We can also throw this exception type in cases where we want to signal to our application that the requested operation through a method call can't be performed because the object is in an invalid state to perform the operation. Carrying on from the example project from the previous section, let’s say we have a new requirement to allow withdrawal transactions on an account. If the withdrawal amount is higher than the account balance, the transaction should fail. We will update the Account class by adding a new Withdraw method as follows:

      public void Withdraw(int amount)
{
  Console.WriteLine("Withdrawing {0} from the {1}'s account", amount, Name);
  if (amount > Balance)
    throw new InvalidOperationException("Insufficient fund");
  Balance = Balance - amount;
  Console.WriteLine($"Transaction completed. Account Balance is {Balance}");
}
    

The method checks if the withdrawal amount is greater than the balance. If it is, it throws InvalidOperationException exception with message saying Insufficient fund. Otherwise, it subtracts the amount from the balance.

Update the code in the try block in the static Main method to be:

      try
{
  var account = new Account("Jimmy Gradle", 900);

  for (int i = 0; i <= 5; i++)
  {
    var amount = 300;

    account.Withdraw(amount);
    Console.WriteLine("Withdrawn {0} from the {1}'s account. \n", amount, account.Name);
  }
}
    

The code above creates an Account object and a loop that iterates five times. On each iteration, the amount of 300 is deducted from the account by calling the Withdraw method. Run the application and you'll get something similar to the following in the console:

      Withdrawing 300 from the Jimmy Gradle's account
Transaction completed. Account Balance is 600
Withdrawn 300 from the Jimmy Gradle's account.

Withdrawing 300 from the Jimmy Gradle's account
Transaction completed. Account Balance is 300
Withdrawn 300 from the Jimmy Gradle's account.

Withdrawing 300 from the Jimmy Gradle's account
Transaction completed. Account Balance is 0
Withdrawn 300 from the Jimmy Gradle's account.

Withdrawing 300 from the Jimmy Gradle's account
Oh no, Something went wrong
System.InvalidOperationException: Insufficient fund
   at MyApp.Program.Account.Withdraw(Int32 amount) in ~/dotnet/MyApp/Program.cs:line 42
   at MyApp.Program.Main(String[] args) in ~/dotnet/MyApp/Program.cs:line 18
    

We got an InvalidOperationException exception with Insufficient fund as the message when looping for the fourth time. From the console output, you should notice that the third iteration left the account with a balance of zero, therefore, calling Withdraw on the fourth iteration caused this exception.

Conclusion

The InvalidOperationException exception is thrown in cases where the failure to invoke a method is caused by reasons other than invalid arguments. Typically, it is thrown when the state of an object cannot support the method call. Because the InvalidOperationException exception can be thrown in a wide variety of circumstances, it is important to read the exception message returned by the Message property. How you handle the exception depends on the specific situation. Most commonly, however, the exception results from developer error and it can be anticipated and avoided.

We looked at an example that showed when it'll be useful to throw the InvalidOperationException from our code. This should leave you equipped to handle and utilize this exception type.