1

Today I have this repeated code:

 public class MyProjectionExpressions
 {
    public static Expression<Func<Log, dynamic>> LogSelector()
    {
        return log => new
        {
            logId = log.LogId,
            message = log.Message,
        };
    }

    public static dynamic LogSelector(Log log)
    {
        return new
        {
            logId = log.LogId,
            message = log.Message,
        };
    }
 }

The first method is a reusable projection expression, which I use like this:

    db.Logs.Select(MyProjectionExpressions.LogSelector());

The second method is used when I'm not dealing with collections, but just one item that needs to be serialized, like this:

    MyProjectionExpressions.LogSelector(someLog);

I tried reusing code, like this:

 public class MyProjectionExpressions
 {
    public static Expression<Func<Log, dynamic>> LogSelector()
    {
        return log => MyProjectionExpressions.LogSelector(log);
    }

    public static dynamic LogSelector(Log log)
    {
        return new
        {
            logId = log.LogId,
            message = log.Message,
        };
    }
 }

But then, I had the "Linq-To-Entities vs Linq-To-Objects" problem, that is: I would have to reuse my projection expression like this:

    db.Logs.ToList().Select(MyProjectionExpressions.LogSelector());

Because MyProjectionExpressions.LogSelector() now contains (uses) a method that is not recognized by Linq-To-Entities:

    LINQ to Entities does not recognize the method 'MyProjectionExpressions.LogSelector()'



Question is, finally:
how can I reuse the lamba expression in a way that Linq-To-Entities continues to work?

This lambda expression:

        log => new
        {
            logId = log.LogId,
            message = log.Message,
        };
sports
  • 7,851
  • 14
  • 72
  • 129
  • 1
    You *really* shouldn't be using `dynamic` here. You should be creating a new named type. Not only will performance improve dramatically due to not needing to be compiling the code to execute this at runtime, but you'll add static type safety and ensure that the compiler can catch any errors in your use of this type's members. It's well worth the 30 seconds it'd take to create a named type with these two properties. – Servy Jun 06 '14 at 18:19

2 Answers2

2

You could do it like this:

 public class MyProjectionExpressions
 {
    public static Expression<Func<Log, dynamic>> LogSelector()
    {
        return log => new
        {
            logId = log.LogId,
            message = log.Message,
        };
    }

    //Get the expression as a Func<Log, dynamic>, then apply it
    //to your log object.
    private static Func<Log, dynamic> impl = LogSelector().Compile();

    public static dynamic LogSelector(Log log)
    {
        return impl(log);
    }
 }
Timothy Shields
  • 75,459
  • 18
  • 120
  • 173
  • awesome... but, i was scared by the comments: is this not efficient? I should ".Compile()" all my functions at the beginning of the application? – sports Jun 06 '14 at 18:55
  • @sports I don't think you'll have an performance issues deriving from the use of `Compile` here. It's only going to happen once, and then calling `impl` will be the same as calling any other normal lambda expression. If you find you're getting bad performance, the liberal use of `dynamic` is a more-likely suspect. – Timothy Shields Jun 06 '14 at 19:32
  • "It's only going to happen once" ..that is because "impl" is static? When is the righthand side, "impl = ..." going to happen? because the class MyProjectionExpressions is never instantiated, in fact it doesnt have a constructor – sports Jun 06 '14 at 19:36
  • 1
    @sports See here: http://stackoverflow.com/questions/1437352/when-is-a-static-constructor-called-in-c – Timothy Shields Jun 06 '14 at 19:37
1

Rather than implementing the expression in terms of the compiled method, implement the complied method in terms of the expression:

public class MyProjectionExpressions
{
    public static Expression<Func<Log, dynamic>> LogSelector()
    {
        return log => new
        {
            logId = log.LogId,
            message = log.Message,
        };
    }
    private static Lazy<Func<Log, dynamic>> func;
    static MyProjectionExpressions()
    {
        func = new Lazy<Func<Log, dynamic>>(() => LogSelector().Compile());
    }
    public static dynamic LogSelector(Log log)
    {
        return func.Value(log);
    }
}

Note that to avoid constantly re-compling the expression every time it needs to be used you can cache the compiled expression and re-use it.

Servy
  • 202,030
  • 26
  • 332
  • 449
  • Reuse, yes. Efficient: not. – H H Jun 06 '14 at 18:16
  • @HenkHolterman Was already working on that. Although it's worth noting that the use of `dynamic` is already going to tank performance noticably. – Servy Jun 06 '14 at 18:17
  • Efficient: better now. Elegant: Not so much. Worth the trouble: doubtful. – H H Jun 06 '14 at 18:19
  • 1
    @HenkHolterman In this exact case, agreed. When in the exact same situation but with a projection that has a ton more columns, or an otherwise more complex projection, then it could be worth it. Either way, whether or not he uses this is a decision he'll need to make now that he's seen what it would take. – Servy Jun 06 '14 at 18:21
  • regarding the comments about efficiency, elegancy, reusable.... can someone put an answer that contains those three? – sports Jun 06 '14 at 18:53