I find myself frequently converting between formats, so I have come up with the following conversion framework:
. The converter interface surfaces a method to convert from a source type to a target type.
The factory is for producing concrete converters.:
This next interface allows for the implementation of a generic converter that you can inject into a class and reuse for many conversions of different types (you can inject the factory instead but the code just looks cleaner with the generic converter).:
Lets look atHere's a simple example to illustrate how to implement these interfaces are implemented. First I will look at the factory as we can provide a pretty generic factory implementation.
The factory implementation introduces a dictionary to keep track of registered converters and the associated constructors for the converters. A registration method is added to allow registration of converters. And finally GetConverterGetConverter
is implemented to look up the converter from the dictionary.
The generic converter can be implemented with a dependency on this factory like so:
Inject a factory into the constructor and then ConvertConvert
can be called for any conversion and the class will get a converter from the factory, run the converter and return the result of the conversion.
Lets introduceHere are some models NOTE:. Note the POCO models, noabsence of dependencies, completely different signatures and very cleancleanliness.
So the plan is to convert from DogDescriptorDogDescriptor
to DogDog
and from CatDescriptorCatDescriptor
to CatCat
. The converters need to implement IConverterIConverter
.
Now we have all the bits and pieces we need to do a conversion.:
var factory = new ConverterFactory();
// register converters
factory.RegisterConverter<DogDescriptor, Dog>(() => new DogConverter());
factory.RegisterConverter<CatDescriptor, Cat>(() => new CatConverter());
var converter = new GenericConverter(factory);
var dog = converter.Convert<DogDescriptor, Dog>(new DogDescriptor{Name = "Spot"});
var cat = converter.Convert<CatDescriptor, Cat>(new CatDescriptor{Number = 666});
Extending conversion support is fairly easy, assumeassuming the two new models are introduced Duckas Duck
and DuckDescriptorDuckDescriptor
. All the developer needs to do is implement a DuckDescriptor to DuckDuckDescriptor
-to-Duck
converter and then register the converter with the factory.
The factory has no dependencies and can easily be tested. The The generic converter needs a mock factory injected for testing. Converters Converters only have dependencies on the models they convert which makes testing converters extremely easy.
Am I reinventing the wheel? I couldn't find anything like it in the .NET framework but I also did not look very hard.
Many conversion implementations extend the model classes with ToType
ToType
style methods. Does this approach offer any advantages?
While I can see the attraction of this approach, it requires an extension method for every conversion which starts getting ugly when you have to do vendor specific conversions of the same models. Using the factory solution, you would simply implement vendor specific factories and inject a generic converter constructed with the vendor specific factory.