Monday, April 22, 2013

Map open generic class to open generic interface in StructureMap

Suppose that you have the following generic interface:

   1: public interface IMapper<T, U>
   2: {
   3:     U Map(T source);
   4: }

And you use Automapper in implementation:

   1: public class Mapper<T, U> : IMapper<T, U>
   2: {
   3:     public U Map(T source)
   4:     {
   5:         return Mapper.Map<T, U>(source);
   6:     }
   7: }

I.e. in your code you will have bunch of mapping interfaces like IMapper<Foo1, Bar1>, IMapper<Foo2, Bar2>, …, which will be implemented by Mapper<Foo1, Bar1>, Mapper<Foo2, Bar2>, …, i.e. by the same class with the same generic parameters. How to configure mapping for these interfaces in StructureMap? First way is to write all possible mappings in the custom registry:

   1: public class MyRegistry : Registry
   2: {
   3:     public MyRegistry()
   4:     {
   5:         Scan(x =>
   6:                  {
   7:                      x.Assembly("MyAssembly");
   8:                  });
   9:         For(typeof(IMapper<Foo1,Bar1>)).Use(typeof(Mapper<Foo1,Bar1>));
  10:         For(typeof(IMapper<Foo2,Bar2>)).Use(typeof(Mapper<Foo2,Bar2>));
  11:         ...
  12:         For(typeof(IMapper<Foo_n,Bar_n>)).Use(typeof(Mapper<Foo_n,Bar_n>));
  13:     }
  14: }

But with this approach you will need to add new mapping for each new pair of classes which you will add in the future. Is there an easier way to define mapping for open generic interface IMapper<T,U> to open generic class Mapper<T,U>? If you would have own class for each mapping (like Foo1Bar1Mapper, Foo2Bar2Mapper, …), then you would be able to use ConnectImplementationsToTypesClosing method, but not in this example, because we have the same class for all mappings. However, it is also possible for our case:

   1: public class MyRegistry : Registry
   2: {
   3:     public MyRegistry()
   4:     {
   5:         Scan(x =>
   6:                  {
   7:                      x.Assembly("MyProcessor");
   8:                  });
   9:         For(typeof(IMapper<,>)).Use(typeof(Mapper<,>));
  10:     }
  11: }

Mapping is defined in line 9. With this configuration Mapper<,> class will be used for all new mappings which you will use in the project.

No comments:

Post a Comment