Getting Started with Adobe After Effects - Part 6: Motion Blur


Upload Image Close it
Select File

Weblog of a workaholic
Browse by Tags · View All
.NET General 53
C# 47
LINQ 16
Dependency injection 12
Validation Application Block 10
Enterprise Library 10
ASP.NET 9
LINQ to SQL 8
Entity Framework 8
CuttingEdge.Conditions 8

Archive · View All
August 2009 7
September 2009 6
March 2007 5
October 2006 3
May 2009 3
July 2008 3
November 2007 3
November 2006 2
January 2009 2
August 2008 2

Simple Injector: Working with multiple constructors

May 28 2011 12:00AM by Steven   

Although limited in features, the Simple Injector has simple but flexible way to add features, such as the possibility to work with multiple constructors.

I read Remo Gloor's weblog today. Remo Gloor is a developer on Ninject. In his latest blog post, he describes a new feature of the coming Ninject release concerning constructor selection. The Ninject team is going to add a new feature that allows developers to configure which constructor overload Ninject should pick to create that type.

I'm not a fan of such a feature, because this steers developers away from a clean application design. Types that act as service components, should contain a single definition of the required dependencies. Since constructor injection is the primary way to inject our dependencies, it doesn't make much sense to have multiple (public) constructors, because we end up with multiple definitions of what dependencies a class requires.

The problem with adding features that support corner case scenario’s is that they tend to pollute the framework’s API. While existing users won't notice the slowly increasing API surface (just like frogs tend to stay in the water when it is heated slowly), new users get overwhelmed. Because of this I try to keep the feature set of Simple Injector minimal. Even the feature set of the SimpleInjector.Extensions library is fairly limited.

Funny thing however, is that such a feature, as Remo is adding in the next Ninject version, is already very easy to implement with the Simple Injector, simply by adding an extension method. Here is an example:

Update [2011-12-13]: This code was updated for the Simple Injector v1.3 release.

public static void Register<TService, TImplementation>(
this Container container, IConstructorSelector selector)
where TService : class
{
container.Register<TService>(() => null);

container.ExpressionBuilt += (sender, e) =>
{
if (e.RegisteredServiceType == typeof(TService))
{
var ctor =
selector.GetConstructor(typeof(TImplementation));

var parameters =
from p in ctor.GetParameters()
select container.GetRegistration(p.ParameterType, true)
.BuildExpression();

e.Expression = Expression.New(ctor, parameters);
}
};
}

This extension method does two things. First it registers the service with a 'fake' delegate. This ensures that nobody can exidentally override the implementation, and it ensures the ExpressionBuilt event will get triggered (since it only gets triggered for registered types). Next it hooks a delegate to the ExpressionBuilt event. The ExpressionBuilt event will get raised every time the container builds an Expression object for the creation of a service type, but before this Expression gets compiled to a Func<T> delegate. This allows us to influence how the container creates a type, which is exactly what we're doing here. When the delegate gets called, we first check whether the event gets raised for our TService (otherwise we skip), and if so, we fetch the constructor we wish to use using the supplied IConstructorSelector instance (shown below). Using this constructor we create a NewExpression instance that allows us to create a new instance of the given TImplementation using retrieved constructor, by supplying it the correct set of parameters.

Here is the IConstructorSelector interface with with a convenient default implementation:

public interface IConstructorSelector
{
ConstructorInfo GetConstructor(Type type);
}

public sealed class ConstructorSelector : IConstructorSelector
{
public static readonly IConstructorSelector MostParameters =
new ConstructorSelector(type => type.GetConstructors()
.OrderByDescending(c => c.GetParameters().Length).First());

public static readonly IConstructorSelector LeastParameters =
new ConstructorSelector(type => type.GetConstructors()
.OrderBy(c => c.GetParameters().Length).First());

private readonly Func<Type, ConstructorInfo> selector;

public ConstructorSelector(Func<Type, ConstructorInfo> selector)
{
this.selector = selector;
}

public ConstructorInfo GetConstructor(Type type)
{
return this.selector(type);
}
}

With this in place, we can simply register a multi constructor type as follows:

container.Register<IService, MyServiceImpl>(
ConstructorSelector.MostParameters);

Because we use Expression objects here, retrieving instances like this pure fire, just as it is with the normal Register<TService, TImplementation>() method.

I like to repeat that I discourage anyone to specify multiple constructors on a type, so the usefulness of this feature is limited. Nevertheless did it give me the possibility to showcase the extendibility of the Simple Injector :-).

Happy injecting.


Republished from .NET Junkie [7 clicks].  Read the original version here [1 clicks].

Steven
395 · 0% · 101
0
Liked
 
0
Lifesaver
 
0
Refreshed
 
0
Learned
 
0
Incorrect



Submit

Your Comment


Sign Up or Login to post a comment.

    Copyright © Rivera Informatic Private Ltd Contact us      Privacy Policy      Terms of use      Report Abuse      Advertising      [ZULU1097]