Updating C# interfaces safely

How can we modify C# interfaces without any breaking changes?

This article is also available on Medium.

Creating any software project from scratch is already an endeavour in itself; but maintaining it and updating it is often quite complex, too! In particular, it can be particularly tricky to update your code if it’s been released and is used by lots of clients all over the world!

Whereas adding new features or fixing bugs should often work out-of-the-box, without any backward compatibility issues, modifying an existing model always requires a bit more preparation…

Typically, remember how in a previous tutorial I discussed how C# interfaces are a great way of structuring your codebase, and defining your objects’ behaviours? Well, those are by definition pretty important to the compiler and, if they’re modified without thinking ahead, they might create some compilation errors for the clients when they get the update… which is of course not very professional!

So, today, let’s see how to safely update those interfaces! 🙂

Important note: the technique I’ll discuss today is only available starting from C# 8.0.

A simple example

Suppose that you are working on a little management game. For now, you have to prepare the base building interface, so that those buildings can have a name, an amount of healthpoints, and a level.

So far, so good – this is pretty straight-forward:

And we can easily create a first type of building using this interface:

Our IBuilding interface imposes the three properties, and so we’re sure that any building will have the required parameters.

But then, suppose we want the buildings to produce some gold each turn based on their current level. How could we do that without forcing any user to change their IBuilding-implementing classes?

Using a default interface method

If we just add the ProduceGold() function as-is in the interface, then the compiler will crash and require us to change the Townhall class… meaning that we have a breaking change!

Rather, what we need to do is benefit from a new C# 8.0 feature: the default interface methods.

Now, because we provided a default implementation, you see that the Townhall class doesn’t need to be updated anymore… however, if you try to call the method directly on your instance, you’ll see that it doesn’t work!

That’s because the method is defined on the interface and not the class that implements it, and this class doesn’t inherit members from the IBuilding interface. So, to access it, we have to cast the Townhall to IBuilding first:

Adding parameters

We’ve seen a way to add our new gold production logic without enforcing any changes on the pre-existing Townhall class. Our default implementation is pretty logical and it should be okay in most cases, however it isn’t very flexible.

For example, what if we wanted to change the level multiplier for gold production, instead of having this hardcoded “magical number”, 5?

Again, we can take advantage of some other C# 8.0 features:

  • interfaces can include static members (both fields and methods)
  • members can also be public, protected or private

All of this allows us to do the following:

Here, I’ve defined a default value for the gold production level multiplier, but I’ve also added a setter to allow users to easily change this value while keeping the same overall implementation:

Extending or overriding the default interface implementation

Still, using parameters isn’t enough if you want to provide your own implementation for the method in your class! For example, let’s say that, for our main building the Townhall, there is a high (constant) gold production for the first levels, to help you start the game.

The solution here is to move the default implementation in a new protected static method in order to make it more “re-usable” in other parts of the code, and in particular in our Townhall class:

From that point on, you’ll see that when you create a new Townhall (that is level 1 by default), the production is of 30 gold coins, and not only 10 🙂

Conclusion

Today, I’ve discussed how C# 8.0 offers some interesting features to update interfaces more safely, like default implementations or static fields. This is essential because it avoids breaking changes and insures a better backward compatibility.

I hope you liked this short tutorial – and feel free to tell me in the comments what other C# topics you’d like to see me write about 🙂

Leave a Reply

Your email address will not be published.