Search code examples
c#expression-trees

Possible to wrap Expression<> and Func<> after Func defined?


I create two kinds of nearly identical mapping functions in my View Models to map from POCOs, one for Queryables and one for Collections. Is it possible to create one method that does both so I can remove the duplicate code? I'd like to only keep the Expression<Func<>> then use it on local Collections and Entity Framework.

public class MyViewModel
{   
    public static readonly Expression<Func<MyPOCO, MyViewModel>> AsMap =
        (e) => new ImportPattern
        {    id = e.id,
             name = e.name
        }

    public static readonly Func<MyPOCO, MyViewModel>> ToMap =
        (e) => new ImportPattern
        {    id = e.id,
             name = e.name
        }

    public int id { get; set; }
    public string name { get; set; }
}

Examples: AsMap succeeds with Entity Framework to project only the fields listed in the mapping function.

var a = Product
        .Where(p => p.id > 0 && p.id < 10)
        .OrderBy(q => q.id)
        .Select( ImportPattern.AsMap );

ToMap successfully works on local Collections.

var products = Products.Where( p => p.id > 0 && p.id < 10).ToList();
var a = products
      .OrderBy(q => q.id)
      .Select( ImportPattern.ToMap );

Using AsMap on local collections fails with a Non-invocable member error. Here's a few more that fail:

.Select( ImportPattern.ToMap.Compile().Invoke() )
.Select( o => ImportPattern.ToMap.Compile().Invoke(o) )

FYI, not looking for an AutoMapper() answer please.


Solution

  • What about

    public static readonly Expression<Func<MyPOCO, MyViewModel>> AsMap =
        (e) => new ImportPattern
        {    id = e.id,
             name = e.name
        }
    
    public static readonly Func<MyPOCO, MyViewModel>> ToMap = AsMap.Compile();
    

    It does not really hurt since you do that only once, but you immediately get rid of the duplicate code.