views:

59

answers:

2

I currently have a mapping setup to convert from one base class to another base class. I am mapping a customer class to a thrid party control. The values are similiar but there is enough differences that I can't reuse the thrid party control.

_converters = new Dictionary<Type, Func<AnnotationBase, AnnotationMark>>();
_converters.Add( typeof( HighlightAnnotation ), ToHighlighterAnnotationMark );
_converters.Add( typeof( RectangleAnnotation ), ToRedactionAnnotationMark );
_converters.Add( typeof( StampAnnotation ), ToTextStampAnnotationMark );

This works find but there are I have to do extra casting in some places. For example:

private AnnotationMark ToTextStampAnnotationMark( AnnotationBase tool )
{
    TextStampAnnotationMark mark = new TextStampAnnotationMark();
    mark.Location = new MarkLocation { X = (int)tool.Location.X, Y = (int)tool.Location.Y };
    mark.Size = new MarkSize { Width = (int)tool.Size.Width, Height = (int)tool.Size.Height };
    mark.Text = ((StampAnnotation)tool).Text;
    return mark;
}

In this example I have to case the AnnotationBase to be StampAnnotation which I know happens to be correct since that is the type registered with the mapper. However I would love to change the signature of this method to be private TextStampAnnotationMark ToTestStampAnnotationMark( StampAnnotaion ).

Is there anyway to make the fuction mapping or behave like this?

Func<TTool,TMark>() 
    where TTool : AnnotationBase 
    where TMark : AnnotationMark

Thanks for your help!

A: 

This doesn't exactly get you away from using any casts, but it does centralize them and make them 'safe':

static class ConvertTest
{
    static IDictionary<Type, IDictionary<Type, Func<AnnotationBase, AnnotationMark>>> _conversions =
        new Dictionary<Type, IDictionary<Type, Func<AnnotationBase, AnnotationMark>>>();

    public static TTo Convert<TFrom, TTo>(this TFrom source)
        where TFrom : AnnotationBase
        where TTo : AnnotationMark
    {
        var conversion = _conversions[typeof(TFrom)][typeof(TTo)];
        return (TTo)conversion(source);
    }

    public static void RegisterConversion<TFrom, TTo>(Func<TFrom, TTo> conversion)
        where TFrom : AnnotationBase
        where TTo : AnnotationMark
    {
        IDictionary<Type, Func<AnnotationBase, AnnotationMark>> toDictionary;

        if (!_conversions.TryGetValue(typeof(TFrom), out toDictionary))
        {
            toDictionary = new Dictionary<Type, Func<AnnotationBase, AnnotationMark>>();
            _conversions.Add(typeof(TFrom), toDictionary);
        }

        toDictionary[typeof(TTo)] = (Func<AnnotationBase, AnnotationMark>)conversion;
    }
}

I haven't tested this code, by the way (it compiles, though :) ).

Daniel Pratt
A: 

Kind of feel stupid that I didn't think of it right way. The simple solution is to cast the object before in the registration.

converters.Add( typeof( StampAnnotation ), 
    tool => ToTextStampAnnotationMark( (StampAnnotation)tool ); 
Jerod Houghtelling