<img height="1" width="1" style="display:none" src="https://www.facebook.com/tr?id=1639164799743833&amp;ev=PageView&amp;noscript=1">
Diagram Views

How Inversion of Control Makes Code More Flexible

Brad McDavid
#Code
Published on December 11, 2014
warren-wong-323107-unsplash-1

Learn how programmers use Inversion of Control to make code more flexible and extensible.

Programming is complicated. Yes, that’s an understatement, but as someone who works with code every day, I’ve found that sometimes there are techniques and methods that I take for granted. I’ve written before about topics like caching and package management, and today I want to look at another technique that can make a programmer’s life easier: Inversion of Control.

Inversion of Control is a way to separate certain tasks or functions in order to make a program more modular, flexible, and extensible.

Understanding Interfaces

In order to understand how Inversion of Control can be used to manage separate functions, we need to take a step back and look at the way classes work in .NET programming. Classes collect certain types of data together and allow you to specify properties and functions of that data. When one class needs to integrate with another class, the best practice approach is to use an interface. This interface is essentially a contract saying that some other bit of functionality will be added to the class. This allows you to separate that functionality out from your class, so that you don’t have to define how it works, you just have to specify that your class will be using it.

For example, you might create a class that contains information about a person (such as first name and last name), and anytime that information is updated, you want to log that activity in a log file. Instead of having the Person class do the actual logging, it will instead use an interface (which we would call ILogger, following the standard convention of naming interfaces starting with the letter “I”) that contains a logging function. The interface does not define how the logging works; it just specifies that there is a logging function.

Managing Associations

In our Person class, the interface would need to be manually associated with a class that implements ILogger every time we create a new person. However, we can use Inversion of Control to manage the associations between classes, eliminating the need for the manual association.

Inversion of Control uses an object called a Container that includes whatever mappings you want to define in your code. That is, it would specify that the ILogger interface will send data to the Logger class. If, in the future, we wanted to create a different logging function, we could create a new class called NewLogger, and in the Container, we can specify that the ILogger interface sends data to NewLogger.

This separation of functionality allows code to be very flexible and extensible, since classes which send data to each other don’t need to know how the other classes work, just that they will do the task they need to do with the data. If one class needs to be updated or changed in some way, it won’t affect any other classes, and the Container which specifies the interfaces between classes will simply need to be modified to use the new version of the class.

Different Types of Containers

Inversion of Control is driven by the Container object, which stores the mappings between classes. There are a number of different container programs available, and they can vary in performance, options, and the syntax used in the code. We often work with StructureMap, which is used by EPiServer, and Unity, which is used by Ektron. I also like to use DryIoc. If you’re interested in learning about the different Containers available, this article delves into the results of some extensive testing done on a large number of the available programs.

Example Code

Let’s look at what the code would look like for the theoretical classes that we mentioned above. The Logger class would be a simple function that sends a message to a log file:

public class Logger : ILogger
{
public void Log(string message)
{
Console.WriteLine("Logger logging the following:" + message);
}
}

The interface for the Logger would be defined as follows:

public interface ILogger
{
void Log(string message);
}

Our Container/Locator maps the ILogger interface to the Logger class:

public static class Locator
{
private static IRegistry Container;

static Locator()
{
Container = new Container();

//Mappings
Container.Register<ILogger, Logger>();
}

public static T Get<T>()
{
return Container.Resolve<T>();
}

public static IEnumerable<T> GetAll<T>()
{
return Container.Resolve<IEnumerable<T>>();
}
}

And this allows our Person class to send data to mapped class that implements the ILogger interface:

public class Person
{
private string _FirstName;
private static ILogger _Logger;
public Person()
{
_Logger = Locator.Get<ILogger>();
}

public string FirstName
{
get
{
return _FirstName;
}
set
{
if(!string.IsNullOrEmpty(_FirstName))
_Logger.Log(_FirstName + " has changed to " + value);

_FirstName = value;
}
}
}

As with many programming techniques, Inversion of Control can be somewhat tricky to grasp at first, but implementing it can greatly improve the flexibility of the code that we write, especially when collaborating with other programmers and using common functions across multiple programs or websites. Do you want to know more about how to use methods like this in your code? Do you have any questions for us about how techniques like this can add functionality to your website? Please contact us to speak with a Solutions Engineer, or feel free to share any other questions you might have in the comments below.