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,
        };
1
  • 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. Commented Jun 6, 2014 at 18:19

2 Answers 2

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);
    }
 }
Sign up to request clarification or add additional context in comments.

4 Comments

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 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.
"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
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.

5 Comments

Reuse, yes. Efficient: not.
@HenkHolterman Was already working on that. Although it's worth noting that the use of dynamic is already going to tank performance noticably.
Efficient: better now. Elegant: Not so much. Worth the trouble: doubtful.
@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.
regarding the comments about efficiency, elegancy, reusable.... can someone put an answer that contains those three?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.