Firstly, I’ve asked this question elsewhere, but meta.stackoverflow.com seems to think that asking the same questions elsewhere is fine, so here goes. I’ll update both if/when I get an answer.
I’m doing a lot of conversion between simple types and I wanted to handle it as nicely as possible. What I thought would be nice would be to be able to do something like this:
var converter = GetMySingletonConverterRegistryPlease();
var somePoint = GetMeSomePointFromSomewhereThanks();
converter.Register<Point, List<int>>(
point => new List<int>{ point.X, point.Y }
);
var someInts = somePoint.To<List<int>>();
So, I came up with the following. Which I’m not at all happy with and would like some advice on (I’ll enumerate why I don’t like it after the code snippet)
public sealed class TypeConverterRegistry : TypeConverterRegistryBase {
public static readonly TypeConverterRegistry Instance = new
TypeConverterRegistry();
static TypeConverterRegistry() {}
TypeConverterRegistry() {}
}
public abstract class TypeConverterRegistryBase {
private readonly Dictionary<object, Delegate> _converters = new
Dictionary<object, Delegate>();
public void Register<TFrom, TTo>( Func<TFrom, TTo> converter ) {
var key = new { From = typeof( TFrom ), To = typeof( TTo ) };
_converters[ key ] = converter;
}
public TTo ConvertTo<TTo>( object from ) {
var key = new { From = from.GetType(), To = typeof( TTo ) };
if( !_converters.ContainsKey( key ) )
throw new KeyNotFoundException(
"No converter has been registered that takes a " + key.From +
" and returns a " + key.To );
var converter = _converters[ key ];
return (TTo) converter.DynamicInvoke( from );
}
}
public static class Extensions {
public static TTo To<TTo>( this object value ) {
return TypeConverterRegistry.Instance.ConvertTo<TTo>( value );
}
}
I don’t like what I’ve done here, because it’s not strongly typed/constrained, it’s easy to accidentally misuse it and get a runtime exception, I’m using object as a catch all, and I also have a bad feeling about the way I’m calling DynamicInvoke and boxing the result. You guys will no doubt see even more problems than that! Also I feel bad about making an extension method on object.
What I do like is the resulting syntax!
So I’d really appreciate any advice, even if it’s just a nudge in the right direction.
Or reassurance that it’s not such a bad way to do it after all 😛
Take a look at AutoMapper (http://automapper.codeplex.com/). While different in intent, your project shares a lot of commonality and you may be able to get a lot from their patterns & code.
In terms of runtime exceptions, this may come down to unit testing since you’re relying on the user registering the type before using it. There’s no way around that and it’s the same thing AutoMapper does but they provide some testing stuff in there too.
I would highly recommend rewriting the ConvertTo method to be generic so that the from parameter is generic instead of type object. You could do that something like:
this would also solve your issue with the extension method. You’d now invoke using: