How to simulate method overloading based on generic return type in c#

I have a read model as IQueryable<CustomType>, I use this inside my Web application. A lot of time I need to extract from this read model different View Model.

I use to write extension method like:

public static ViewModelA AsViewModelA(this IQueryable<CustomType> query) 
{ 
    var vm = view
              .Select(x => new ViewModelA
              {
                  Something = x.Something
              }).FirstOrDefault();

    return vm;
}

public static ViewModelB AsViewModelB(this IQueryable<CustomType> query) 
{
    var vm = view
              .Select(x => new ViewModelB
              {
                  SomethingElse = x.SomethingElse
              }).FirstOrDefault();

    return vm;
}

This do the job but I don't like the mess generated with method names; a more generic way, something like this would be preferable:

query.AsViewModel<ViewModelA>()

I know that return type is not intended as method signature (so no overload applies) and I know that generic type is not sufficient to make an overload. What I would is a mechanism to just simulate overloading based on generic type. This mechanism should avoid a main method with cascading if/then/else. There is a way? Maybe with dynamics?

Jon Skeet
people
quotationmark

One option is to have a map from the type to a conversion of CustomType to that type. So it would look something like:

private static readonly Dictionary<Type, Expression> Mappings = 
    new Dictionary<Type, Expression>
    {
        { typeof(ViewModelA),
          Helper<ViewModelA>(x => new ViewModelA { Something = x.Something }) },
        { typeof(ViewModelB),
          Helper<ViewModelB>(x => new ViewModelB { SomethingElse = x.SomethingElse }) },
        ...
    }

// This method just helps avoid casting all over the place.
// In C# 6 you could use an expression-bodied member - or add a 
private static Expression<Func<CustomType, T>> Helper<T>
    (Expression<Func<CustomType, T>> expression)
{
    return expression;
}

public static T AsViewModel<T>(this IQueryable<CustomType> query) 
{ 
    Expression rawMapping;
    if (!Mappings.TryGetValue(typeof(T), out rawMapping))
    {
        throw new InvalidOperationException("Or another exception...");
    }
    // This will always be valid if we've set up the dictionary properly
    var mapping = (Expression<Func<CustomType, T>>) rawMapping;
    return view.Select(mapping).FirstOrDefault();
}

You can make the dictionary construction a bit cleaner with a bit more up-front code.

people

See more on this question at Stackoverflow