Implementing Inversion of Control

You might be asking yourself at this point in time, how do I switch out different classes such as the ISettings example? Inversion of Control (IoC) is a design pattern meant to complement dependency injection and solve this problem. The basic principle is that many of the objects created throughout your application are managed and created by a single class. Instead of using the standard C# constructors for your ViewModel or Model classes, a service locator or factory class would manage them throughout the application.

There are many different implementations and styles of IoC, so let's implement a simple service locator class to use through the remainder of this book as follows:

public static class ServiceContainer
{
  static readonly Dictionary<Type, Lazy<object>> services =new Dictionary<Type, Lazy<object>>();

  public static void Register<T>(Func<T> function)
  {
    services[typeof(T)] = new Lazy<object>(() => function());
  }

  public static T Resolve<T>()
  {
    return (T)Resolve(typeof(T));
  }

  public static object Resolve(Type type)
  {
    Lazy<object> service;
    if (services.TryGetValue(type, out service)
    {
      return service.Value;
    }
    throw new Exception("Service not found!");
  }
}

This class is inspired by the simplicity of XNA/MonoGame's GameServiceContainer class, and follows the service locator pattern. The main differences are the heavy use of generics and the fact that it is a static class.

To use our ServiceContainer class, we would declare the version of ISettings or other interfaces that we want to use throughout our application by calling Register as seen in the following lines of code:

//iOS version of ISettings
ServiceContainer.Register<ISettings>(() => new AppleSettings());

//Android version of ISettings
ServiceContainer.Register<ISettings>(() => new DroidSettings());

//You can even register ViewModels
ServiceContainer.Register<SettingsViewModel>(() => new SettingsViewModel());

On iOS, you could place this registration code in either your static void Main() method or in the FinishedLaunching method of your AppDelegate class. These methods are always called before the application is started.

On Android, it is a little more complicated. You cannot put this code in the OnCreate method of your activity, set as the main launcher. In some situations, the OS can close your application but restart it later in another activity. This situation is likely to cause an exception to be raised. The guaranteed safe place to put this is in a custom Android Application class, which has an OnCreate method that is called prior to any activities being created in your application. The following lines of code show the use of the Application class:

[Application]
public class Application : Android.App.Application
{
  //This constructor is required
  public Application(IntPtr javaReference, JniHandleOwnership transfer): base(javaReference, transfer)
  {

  }

  public override void OnCreate()
  {
    base.OnCreate();

    //IoC Registration here
  }
}

To pull a service out of the ServiceContainer class, we could rewrite the constructor of the SettingsViewModel class like the following lines of code:

public SettingsViewModel()
{
  this.settings = ServiceContainer.Resolve<ISettings>();
}

Likewise, you would use the generic Resolve method to pull out any ViewModel classes you would need to call from within controllers on iOS or activities on Android. This is a great, simple way to manage dependencies within your application.

There are, of course, some great open source libraries out there that implement IoC for C# applications. You might consider switching to one of them if you need more advanced features for service location, or just want to graduate to a more complicated IoC container.

Here are a few libraries that have been used with Xamarin projects:

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.114.94