Author avatar

Peter Mbanugo

Commonly Encountered Exceptions- InvalidOperationException

Peter Mbanugo

  • Nov 9, 2018
  • 8 Min read
  • 22,376 Views
  • Nov 9, 2018
  • 8 Min read
  • 22,376 Views
C#

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:

1using System;
2using System.Collections.Generic;
3
4namespace MyApp
5{
6  class Program
7  {
8    static void Main(string[] args)
9    {
10      try
11      {
12        var accounts = new List<Account>() {
13          new Account("Jimmy Gradle", 900),
14          new Account("Sophie Gradle", 300)
15        };
16
17        Console.WriteLine("Looping through available accounts");
18
19        foreach (Account account in accounts)
20        {
21          Console.WriteLine("{0} has {1} dollars", account.Name, account.Balance);
22          if (account.Name == "Sophie Gradle")
23          {
24            var newAccount = new Account("Jeremy brown", 1500);
25            Console.WriteLine("Adding {0} to the collection...\n", newAccount.Name);
26            accounts.Add(newAccount);
27          }
28        }
29      }
30      catch (InvalidOperationException ex)
31      {
32        Console.WriteLine("Oh no, Something went wrong");
33        Console.WriteLine(ex.Message);
34      }
35    }
36
37    class Account
38    {
39      public Account(string name, int balance)
40      {
41        Name = name;
42        Balance = balance;
43      }
44
45      public string Name { get; private set; }
46      public int Balance { get; private set; }
47    }
48  }
49}
csharp

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.

1Looping through available accounts
2Jimmy Gradle has 900 dollars
3Sophie Gradle has 300 dollars
4Adding Jeremy brown to the collection...
5
6Oh no, something went wrong
7Collection 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:

1var accounts = new List<Account>() {
2  new Account("Jimmy Gradle", 900),
3  new Account("Sophie Gradle", 300)
4};
5Console.WriteLine("Looping through available accounts");
6
7int count = accounts.Count - 1;
8for (int index = 0; index <= count; index++)
9{
10  var account = accounts[index];
11  Console.WriteLine("{0} has {1} dollars", account.Name, account.Balance);
12  if (account.Name == "Sophie Gradle")
13  {
14    var newAccount = new Account("Jeremy brown", 1500);
15    Console.WriteLine("Adding {0} to the collection… \n", newAccount.Name);
16    accounts.Add(newAccount);
17  }
18}
csharp

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:

1Looping through available accounts
2Jimmy Gradle has 900 dollars
3Sophie Gradle has 300 dollars
4Adding 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:

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

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:

1try
2{
3  var account = new Account("Jimmy Gradle", 900);
4
5  for (int i = 0; i <= 5; i++)
6  {
7    var amount = 300;
8
9    account.Withdraw(amount);
10    Console.WriteLine("Withdrawn {0} from the {1}'s account. \n", amount, account.Name);
11  }
12}
csharp

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:

1Withdrawing 300 from the Jimmy Gradle's account
2Transaction completed. Account Balance is 600
3Withdrawn 300 from the Jimmy Gradle's account.
4
5Withdrawing 300 from the Jimmy Gradle's account
6Transaction completed. Account Balance is 300
7Withdrawn 300 from the Jimmy Gradle's account.
8
9Withdrawing 300 from the Jimmy Gradle's account
10Transaction completed. Account Balance is 0
11Withdrawn 300 from the Jimmy Gradle's account.
12
13Withdrawing 300 from the Jimmy Gradle's account
14Oh no, Something went wrong
15System.InvalidOperationException: Insufficient fund
16   at MyApp.Program.Account.Withdraw(Int32 amount) in ~/dotnet/MyApp/Program.cs:line 42
17   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.