142

Going from a lambda to an Expression is easy using a method call...

public void GimmeExpression(Expression<Func<T>> expression)
{
    ((MemberExpression)expression.Body).Member.Name; // "DoStuff"
}

public void SomewhereElse()
{
    GimmeExpression(() => thing.DoStuff());
}

But I would like to turn the Func in to an expression, only in rare cases...

public void ContainTheDanger(Func<T> dangerousCall)
{
    try 
    {
        dangerousCall();
    }
    catch (Exception e)
    {
        // This next line does not work...
        Expression<Func<T>> DangerousExpression = dangerousCall;
        var nameOfDanger = 
            ((MemberExpression)dangerousCall.Body).Member.Name;
        throw new DangerContainer(
            "Danger manifested while " + nameOfDanger, e);
    }
}

public void SomewhereElse()
{
    ContainTheDanger(() => thing.CrossTheStreams());
}

The line that does not work gives me the compile-time error Cannot implicitly convert type 'System.Func<T>' to 'System.Linq.Expressions.Expression<System.Func<T>>'. An explicit cast does not resolve the situation. Is there a facility to do this that I am overlooking?

Dave Cameron
  • 2,110
  • 2
  • 19
  • 23
  • I don't really see much use for the 'rare case' example. The caller is passing in the Func. There is no need to repeat back to the caller what that Func was (via the exception). – Adam Ralph Dec 20 '11 at 19:54
  • 2
    The exception is not handled in the caller. And, because there are multiple call sites passing in different Funcs, catching the exception in the caller creates duplication. – Dave Cameron May 03 '12 at 19:12
  • 1
    The exception stack trace is designed to show this information. If the exception is thrown within the invocation of the Func, this will show in the stack trace. Incidentally, if you were to choose to go the other way, i.e. accept an expression and compile it for invocation, you would lose this since the stack trace would show something like `at lambda_method(Closure )` for the invocation of the compiled delegate. – Adam Ralph May 03 '12 at 20:53
  • I guess you should look at the answer in this [link][1] [1]: http://stackoverflow.com/questions/9377635/create-expression-from-func/9377714#9377714 – Ibrahim Kais Ibrahim Jan 26 '14 at 13:21

9 Answers9

114

Ooh, it's not easy at all. Func<T> represents a generic delegate and not an expression. If there's any way you could do so (due to optimizations and other things done by the compiler, some data might be thrown away, so it might be impossible to get the original expression back), it'd be disassembling the IL on the fly and inferring the expression (which is by no means easy). Treating lambda expressions as data (Expression<Func<T>>) is a magic done by the compiler (basically the compiler builds an expression tree in code instead of compiling it to IL).

Related fact

This is why languages that push lambdas to the extreme (like Lisp) are often easier to implement as interpreters. In those languages, code and data are essentially the same thing (even at run time), but our chip cannot understand that form of code, so we have to emulate such a machine by building an interpreter on top of it that understands it (the choice made by Lisp like languages) or sacrificing the power (code will no longer be exactly equal to data) to some extent (the choice made by C#). In C#, the compiler gives the illusion of treating code as data by allowing lambdas to be interpreted as code (Func<T>) and data (Expression<Func<T>>) at compile time.

Edward Brey
  • 40,302
  • 20
  • 199
  • 253
Mehrdad Afshari
  • 414,610
  • 91
  • 852
  • 789
  • 4
    Lisp doesn't have to be interpreted, it can easily be compiled. Macros would have to be expanded at compile time, and if you want to support `eval` you would need to start up the compiler, but other than that, there's no problem at all doing that. – configurator May 30 '11 at 12:02
  • 4
    "Expression> DangerousExpression = () => dangerousCall();" is not easy? – mheyman Feb 17 '14 at 21:19
  • 13
    @mheyman That would create new `Expression` about your wrapper action, but it would have no expression tree info about internals of `dangerousCall` delegate. – Nenad Dec 05 '14 at 20:55
51
    private static Expression<Func<T, bool>> FuncToExpression<T>(Func<T, bool> f)  
    {  
        return x => f(x);  
    } 
Override
  • 615
  • 5
  • 2
  • 1
    I wanted to traverse the syntax tree of the returned expression. Would this approach allow me to do that? – Dave Cameron Mar 15 '11 at 13:58
  • 12
    @DaveCameron - No. See above answers - the already compiled `Func` will be hidden in a new Expression. This simply adds one layer of data over code; you could traverse one layer just to find your parameter `f` without further details, so you're right where you started. – Jonno Mar 01 '12 at 13:43
  • It causes client evaluation exceptions for entity framework core. – XAMT Sep 26 '21 at 18:12
  • @XAMT were you able to solve the exception? Thanks in advance! – Luca Sep 01 '22 at 22:03
  • @Luca, You should change the statement to what is understandable to EF. (e.g. change `.Equal()` to `== x.ToLower()` – XAMT Sep 03 '22 at 03:34
26

What you probably should do, is turn the method around. Take in an Expression>, and compile and run. If it fails, you already have the Expression to look into.

public void ContainTheDanger(Expression<Func<T>> dangerousCall)
{
    try 
    {
        dangerousCall().Compile().Invoke();;
    }
    catch (Exception e)
    {
        // This next line does not work...
        var nameOfDanger = 
            ((MemberExpression)dangerousCall.Body).Member.Name;
        throw new DangerContainer(
            "Danger manifested while " + nameOfDanger, e);
    }
}

public void SomewhereElse()
{
    ContainTheDanger(() => thing.CrossTheStreams());
}

Obviously you need to consider the performance implications of this, and determine if it is something that you really need to do.

David Wengier
  • 10,061
  • 5
  • 39
  • 43
11

If you sometimes need an expression and sometimes need a delegate, you have 2 options:

  • have different methods (1 for each)
  • always accept the Expression<...> version, and just .Compile().Invoke(...) it if you want a delegate. Obviously this has cost.
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
10

NJection.LambdaConverter is a library that converts a delegate to an expression

public class Program
{
    private static void Main(string[] args) {
       var lambda = Lambda.TransformMethodTo<Func<string, int>>()
                          .From(() => Parse)
                          .ToLambda();            
    }   
        
    public static int Parse(string value) {
       return int.Parse(value)
    } 
}
Sagi
  • 8,972
  • 3
  • 33
  • 41
8

You can go the other way via the .Compile() method however - not sure if this is useful for you:

public void ContainTheDanger<T>(Expression<Func<T>> dangerousCall)
{
    try
    {
        var expr = dangerousCall.Compile();
        expr.Invoke();
    }
    catch (Exception e)
    {
        Expression<Func<T>> DangerousExpression = dangerousCall;
        var nameOfDanger = ((MethodCallExpression)dangerousCall.Body).Method.Name;
        throw new DangerContainer("Danger manifested while " + nameOfDanger, e);
    }
}

public void SomewhereElse()
{
    var thing = new Thing();
    ContainTheDanger(() => thing.CrossTheStreams());
}
Steve Willcock
  • 26,111
  • 4
  • 43
  • 40
7
 Expression<Func<T>> ToExpression<T>(Func<T> call)
        {
            MethodCallExpression methodCall = call.Target == null
                ? Expression.Call(call.Method)
                : Expression.Call(Expression.Constant(call.Target), call.Method);

            return Expression.Lambda<Func<T>>(methodCall);
        }
Dmitry Dzygin
  • 1,258
  • 13
  • 26
  • Can you elaborate the "this will not work" part? Have you actually tried compiling and executing it? Or it doesn't work particularly in your application? – Dmitry Dzygin Oct 15 '15 at 14:13
  • 1
    FWIW, this might not be what the main ticket was about, but it was what I needed. It was the `call.Target` part that was killing me. It worked for years, and then suddenly stopped working and started complaining about a static/non-static blah blah. Anyway, thanks! – Eli Gassert Nov 23 '16 at 08:42
  • I've been using Override's answer for years but my expression now contains a `Span` which won't work. This is essentially the same thing but works with `Span`. – Josh Close Jan 08 '21 at 16:33
3

JB Evain from the Cecil Mono team is doing some progress to enable this

http://evain.net/blog/articles/2009/04/22/converting-delegates-to-expression-trees

aaguiar
  • 102
  • 3
-1

Change

// This next line does not work...
Expression<Func<T>> DangerousExpression = dangerousCall;

To

// This next line works!
Expression<Func<T>> DangerousExpression = () => dangerousCall();
mheyman
  • 4,211
  • 37
  • 34
  • Servy, it as absolutely legal way to get an expression. syntax sugar to build it though expression.lambda and expression.call. Why do you think it should fail at runtime? – Roman Pokrovskij Nov 13 '17 at 12:40