flow.
"Flow is a condition of deep, nearly meditative involvement." - Tom DeMarco

Poor Man's Dependency Injection using Generics

Thursday, September 06, 2007 11:37 AM
Not many people would argue the value of dependency injection, especially when it comes to replacing a live object with a faked object for testing.  Although most implementations of this take advantage injecting the faked object into the constructor of the consuming object at instantiation time, did you know that there's another way to easily swap objects in and out using generics?

Here's how...
Imagine you have a data access layer which depends on a valid database connection.  You don't want to use a real database in testing do you?  Of course not.  So how do you handle the situation?  You abstract the database connection out to an interface and provide a fake implementation of that same interface, often using mock objects.  Take the example below, here we have an IConnection interface which represents a data connection.  However, we've implemented a FakeConnection class which simply contains an underlying list of Customers instead a live connection to an actual database.  Using traditional dependency injection, we simply "inject" the fake implementation into the DataLayer's constructor at creation time.  Since the FakeConnection also implements the IConnection interface the DataLayer doesn't know the difference...


        /// <summary>

        /// Initializes a new instance of the <see cref="DataLayer&lt;T&gt;"/> class.

        /// </summary>

        /// <param name="connection">The connection.</param>

        public DataLayer(IConnection connection)

        {

            _connection = connection;

        }



 

            FakeConnection fakeConnection = new FakeConnection();

            DataLayer dataLayer = new DataLayer(fakeConnection);



However, using generics and constraints, you can accomplish this same technique.  Here is the declaration of the class that could accept an IConnection object as an interface...

 

    /// <summary>

    /// Represents a actual data layer.

    /// </summary>

    /// <typeparam name="T">The type of the connection to use.</typeparam>

    public class DataLayer<T> where T : IConnection, new()

    {

       . . .

    }



And here's how one would consume this class...

 

            DataLayer<FakeConnection> dataLayer =

                new DataLayer<FakeConnection>();



The difference lies in the fact that we don't have to explicitly create an instance of FakeConnection before passing it to the DataLayer.  The DataLayer's constructor will create the instance for us automatically using the following code...

 

        /// <summary>

        /// Initializes a new instance of the <see cref="DataLayer{T}"/> class.

        /// </summary>

        public DataLayer()

        {

            _connection = (T)Activator.CreateInstance(typeof(T));

        }



Note the use of the new() constraint in the signature of the DataLayer<T> class.  This is a result of our dependence on the Activator class in the DataLayer's constructor above to create our instance of IConnection via reflection.

I've included the source code of a small working project using this technique so you can get the full picture.  However, I'll leave it as an exercise to the reader to determine if this technique is actually worthwhile.  It could be argued that less code is required by the consumer class as the creation of the appropriate instance of IConnection is encapsulated in the DataLayer.  However, this additional responsibility of the DataLayer could arguably be considered out of scope for the object and would definitely complicate the creation of an object with a valid connection string.

Let me know what you think.  And if you're interested in more information, Michael Feathers discusses this technique briefly in his highly recommended book Working Effectively with Legacy Code.

kick it on DotNetKicks.com

Feedback

 re: Poor Man's Dependency Injection using Generics

The new() generic restraint not only guarantees a parameterless constructor but also allows you to call the constructor directly, without reflection:

public T Test<T>()
where T: new()
{
return new T();
} 9/19/2007 11:29 AM | Nathan Baulch

# re: Poor Man's Dependency Injection using Generics

I like it! Simple. Elegant.

The only thing it doesn't buy you is the ability to manipulate the Connection at run-time before you pass it into the data layer, like a "Rich Man"'s dependency injection framework might allow.

Not that I think this is a fatal flaw, just pointing out the pros and cons. :)

I think this will work nicely in a whole lotta situations. 9/19/2007 1:02 PM | Haacked

 re: Poor Man's Dependency Injection using Generics

So instead of

DataLayer dl = new DataLayer(new FakeConnection());

you have

DataLayer<FakeConnection> dl =new DataLayer<FakeConnection>();

I don't get it? What is this buying you? 9/19/2007 5:02 PM | Tim

# re: Poor Man's Dependency Injection using Generics

mmmm.....
I don’t completely like it. I like your idea of a generic class, which is injected. But what I don’t like is that this generic class is Auto-Injected, I don’t like the idea of a class that auto injects, because you will have a lot of construction responsibility distributed in a lot of classes In your application.

Bye!
9/20/2007 9:47 AM | Mariano Vicario

# re: Poor Man's Dependency Injection using Generics

If you are already using mocks, why the need for the generics thing? Ayende does it all for you,
IConnection conn = mocks.Stub<IConnection>();
DataLayer dl = new DataLayer(conn);
I like it, just trying to see how it's an improvement over mocks. 9/20/2007 7:34 PM | Chris Carter

# re: Poor Man's Dependency Injection using Generics

Thanks! Nathan, I actually didn't know that I didn't have to use the Activator there. You're right, with the normal 'new' construction the code becomes a lot clearer.

Thanks!
Jeremy 9/20/2007 9:27 PM | Jeremy

 re: Poor Man's Dependency Injection using Generics

i use generics all over the place for my mocks, as you suggest. the problem is that my unit test code needs access to the specific mock instances to set them up and to validate that they were manipulated properly after the test ends. so having a "new()" constraint doesn't help because my test code needs to instantiate the object. i end up exposing the mock as a get+set property of the object like this:

class DataLayer<T> where T:IConnection {
T Connection { get; set; }
}

this allows my test code to easily manipulate the mock and instantiate it without a separate variable defined outside the scope of the class. my test code looks like this...

DLayer<MockConn> d = new DLayer<MockConn>();
d.Connection.MockReturnValue = ...

The problem I have run into is that my higher level classes end up with a ridiculously long list of type parameters...

class HighLevel<A,B,C<C1,C2,C3>,D,E<E1,E2>> {...}
4/2/2008 11:51 PM | justin

Post a comment





 

Please add 8 and 4 and type the answer here: