2

I've become quite familiar with Dependency Injection and the power of loosely-coupled components. When I sought to enhance or build on that for educational purposes I stumbled across a problem:

public interface IReader<TParameter, TOutput>
{
     TOutput Read(TParameter parameter);
}

public class Customer : IReader<int, CustomerModel>
{
     public CustomerModel Read(int parameter)
     {      
          // Implementation...
     }
}

The problem comes when you attempt to use Dependency Injection. I attempted:

public class Reader<TParameter, TOutput>
{
     private IReader<TParameter, TOutput> reader;
     public Reader(IReader<TParameter, TOutput> reader)
     {
          // Link through Constructor... 
     }
}

That doesn't work, but at this stage how can you implement and perform Dependency Injection when a generic is involved at this level? Is it even possible?

Greg
  • 11,302
  • 2
  • 48
  • 79
  • Which IoC container are you using? I know for Unity you should be able to use `container.RegisterType, Customer>()` other frameworks might be more limited. – Jarga Jan 12 '15 at 03:42
  • @Jarga None at the moment, wanted to to attempt the premise simple without a IoC Framework first. – Greg Jan 12 '15 at 03:43
  • See if this link answers your question: http://stackoverflow.com/questions/700966/generic-type-in-constructor [1]: – wigs Jan 12 '15 at 03:51
  • I made a mistake in the comment above, you would need to do `container.RegisterType, Customer>()` in Unity. Either way, if you are rolling your own then you should be able to match the type`IReader` the same way you would other interface types. – Jarga Jan 12 '15 at 03:57
  • Sorry, but I am honestly trying to understand the problem here. To start with, it might be beneficial to rename the classes. Customer which implements IReader, and Reader that depends on IReader, but does not implement it?! I would suggest renaming Customer to CustomerReader (is it really reading a customer object, or just creating a model given an integer?) And when you say "that doesn't work", what is the problem you run into with these classes? – sudheeshix Jan 12 '15 at 04:38
  • Your problem seems to be more your understanding of generics than of generics with DI. Most DI frameworks have mechanisms for using generics, and its trivial to use generics with poor mans DI, but the problem in your example is that your syntax doesn't work. See Jason's example. – Erik Funkenbusch Jan 12 '15 at 17:59
  • @ErikFunkenbusch I know the syntax doesn't work, I'm trying to become familiar with such an approach clarification would be terrific. – Greg Jan 12 '15 at 18:02

1 Answers1

1

I agree with some of the comments that without an IOC framework or a fair bit of custom reflection, you're not going to get much out of DI with simple .NET for generics like this situation. The pattern you seem to be describing is a Proxy pattern with the last Reader class that encapsulates the interface.

By renaming the last class ReaderProxy for clarity, I tried to take your code a step farther hoping to show how the dependency injection can be carried through without the framework or custom initialization of the generic objects that could simplify the actual initialization lines.

The code below would show how dependency injection could be used (See fiddle: https://dotnetfiddle.net/cfNCyl).

var reader = new ReaderProxy<int, CustomerModel>(new Customer());
var model = reader.Read(5);
Console.WriteLine(model.Id);

And here are the classes and interfaces required for the above code (including a simple CustomerModel):

public interface IReader<TParameter, TOutput>
{
     TOutput Read(TParameter parameter);
}

public class Customer : IReader<int, CustomerModel>
{
     public CustomerModel Read(int parameter)
     {      
         return new CustomerModel() { Id = parameter };
     }
}

public class CustomerModel
{
    public int Id { get; set; }
}

public class ReaderProxy<TParameter, TOutput>
    : IReader<TParameter, TOutput>
{
    private IReader<TParameter, TOutput> reader;
    public ReaderProxy(IReader<TParameter, TOutput> reader)
    {
          this.reader = reader;
    }
    public TOutput Read(TParameter parameter)
    {
        return this.reader.Read(parameter);
    }
}
Jason W
  • 13,026
  • 3
  • 31
  • 62