Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the string (of source-code) that generated a lambda-expression?

(for LISP hackers in short: I'm looking for the LISP-quote equivalent in C#)

I'm trying to write a meaningful ToString-method for a class which has a Func as member. Experiened API-users can set this member via setter-method like

myClassObject.SetFunction( (x) => x*x );

Now, when I use the ToString-method on the member it only returns

System.Func<double,double>

which is not very helpful. What would be helpful is

"(x) => x*X"

Is there any (preferable easy) way to do that?

Thanks for any help or comments.

Edit: corrected some typos

like image 746
Michael Schober Avatar asked Sep 01 '11 14:09

Michael Schober


3 Answers

Expression<Func<double,double>> expr = x => x * x;
string s = expr.ToString(); // "x => (x * x)"
like image 84
Thomas Levesque Avatar answered Oct 14 '22 05:10

Thomas Levesque


If you're willing to store your delegate as an expression, you can achieve what you want. The code would look something like this:

private Expression<Func<double, double>> myFunc;
private Func<double, double> cachedDelegate; 

public void SetFunc(Expression<Func<double,double>> newFunc)
{
    this.myFunc = newFunc;
    this.cachedDelegate = null;
}

public double ExecFunc(double x)
{
    if (this.myFunc != null)
    {
        if (this.cachedDelegate != null)
        {
            return this.cachedDelegate(x);
        }
        else
        {
            this.cachedDelegate = this.myFunc.Compile();
            return this.cachedDelegate(x);
        }
    }

    return 0.0;
}

public string GetFuncText()
{
    if (this.myFunc != null)
    {
        return this.myFunc.ToString();
    }
    return "";
}

In order to actually use the lambda expression, you have to compile it first. Storing it in a delegate means you only take that hit once.

Also, this approach means that users have to use a lambda, since method groups aren't convertible to Expression<Func<>>. That's not a huge concern, though, since instead of passing MyMethod, a user could pass x => MyMethod(x).

The calling code would look something like this:

myObject.SetFunc(x => 2*x);
Console.WriteLine(myObject.GetFuncText());

One final note is that the above sample is not thread-safe, so if you expect to have the methods called from multiple threads, some sort of synchronization would be appropriate.

like image 30
dlev Avatar answered Oct 14 '22 07:10

dlev


None that I know of since that string has never entered the system, only IL was somehow generated and stored with a reference... you would need to "decompile" the IL to some meaningful string...

With CodeExpression there is possibility to call GenerateCodeFromExpression via an instance of CodeDomProvider which has built-in implementations for C# / VB / JScript... but I would be surprised if that met your needs...

Another option: With Expression you could use ToString() - this works with LambdaExpression too since that is just a descendant.

like image 1
Yahia Avatar answered Oct 14 '22 05:10

Yahia