Static Initialization

Constructor injection is a great way to keep all class dependencies easily visible in a constructor parameter list and makes unit testing easier. There are times when this isn’t possible such as another class initializes your class and you don’t have control of its construction. This presents a challenge. Normally this results in relenting to using a service locator to pull in your dependencies. Sure its easy but using a service locator has just added hidden dependencies to your class. A common example is a markup extension in Xaml, which is initialized via the Xamarin Forms framework.

To resolve this we can do what I call static initialization, where we use a function to inject the dependencies into a constructor and hold them in a static value inside the class for all instances to use. I use this in the Exrin Framework, hence if you already use that framework, its available to use without implementing everything below.

architecture

Interface

First I create an interface that I add to the class that I don’t construct myself. This allows me to find it later via reflection.

public interface IStaticInitialize {}

Attribute

I also create an Attribute that I will put on the constructor I will be injecting into.

public class StaticInitialize: Attribute

Static Constructor Initialize

Next lets create the constructor with the attribute. Remember that we must also have a parameter less constructor as well so the existing class construction continues to work.

public class Example
{
     private static IExampleService _exampleService;

     [StaticInitialize]
     public Example(IExampleService exampleService)
     {
         _exampleService = exampleService;
     }

     public Example() {}
}

Bootstrapper

Bringing it all together in the bootstrapper, I will find all classes implementing IStaticInitialize and load the constructor with the StaticInitialize Attribute. This is where the magic happens and you just need to call this function inside your bootstrapper or upon the loading of your app.

public void StaticInitialize(AssemblyName assemblyName)
{    
    foreach (var type in AssemblyHelper.GetTypes(assemblyName, typeof(IStaticInitialize)))
    {
        var useConstructor = type.DeclaredConstructors.Where(c => c.CustomAttributes.Any(x => x.AttributeType == typeof(StaticInitialize))).First();

        List<object> parameters = new List<object>();
        foreach (var parameter in useConstructor.GetParameters())
            parameters.Add(YourServiceLocator.Get(parameter.ParameterType));

        Activator.CreateInstance(type.AsType(), parameters.ToArray());
    }
 }

// AssemblyName can be obtained from any object within the assembly you want to scan. 
// Take any object type in your project as such
_myObjectInstance.GetType().GetTypeInfo().Assembly.GetName();

Minor Warning

You need to be mindful of memory leaks and possible state issues, while using this method to pass in dependencies. Remember the static reference will be available across all instances, but since the ServiceLocator would be pulling in a global instance this tends not to be of concern when switching to this method. Since these are static references you will have to remember to manually dispose of them if needed. Again this tends not to be applicable as I rarely see anyone dispose of instances they placed into the Dependency Injection Container.

Microsoft MVP | Xamarin MVP | Xamarin Certified Developer |
Exrin MVVM Framework | Xamarin Forms Developer | Melbourne, Australia

Related Posts

Leave A Comment?