Как получить строку (из исходного кода), которая сгенерировала лямбда-выражение? - PullRequest
6 голосов
/ 01 сентября 2011

(короче говоря, для LISP-хакеров: я ищу эквивалент LISP-цитаты в C #)

Я пытаюсь написать значимый метод ToString для класса, в котором в качестве члена используется Func. Опытные пользователи API могут установить этот элемент с помощью метода setter, например

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

Теперь, когда я использую метод ToString для члена, он возвращает только

System.Func<double,double>

, что не очень полезно. Что было бы полезно, это

"(x) => x*X"

Есть ли какой-нибудь (предпочтительный простой) способ сделать это?

Спасибо за любую помощь или комментарии.

Редактировать: исправлены некоторые опечатки

Ответы [ 3 ]

8 голосов
/ 01 сентября 2011
Expression<Func<double,double>> expr = x => x * x;
string s = expr.ToString(); // "x => (x * x)"
1 голос
/ 01 сентября 2011

Если вы хотите сохранить своего делегата в качестве выражения, вы можете достичь того, чего хотите. Код будет выглядеть примерно так:

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 "";
}

Чтобы реально использовать лямбда-выражение, сначала нужно скомпилировать его. Хранение его в делегате означает, что вы получаете этот удар только один раз.

Кроме того, этот подход означает, что пользователи должны использовать лямбду, поскольку группы методов не могут быть преобразованы в Expression<Func<>>. Это не большая проблема, поскольку вместо передачи MyMethod пользователь может передать x => MyMethod(x).

Код вызова будет выглядеть примерно так:

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

И последнее замечание: приведенный выше пример не является потокобезопасным, поэтому, если вы ожидаете, что методы будут вызываться из нескольких потоков, будет уместна какая-то синхронизация.

1 голос
/ 01 сентября 2011

Ничего из того, что мне известно, поскольку эта строка никогда не поступала в систему, только IL был каким-то образом сгенерирован и сохранен со ссылкой ... вам нужно будет "декомпилировать" IL в какую-то значимую строку ...

С CodeExpression существует возможность вызова GenerateCodeFromExpression через экземпляр CodeDomProvider, который имеет встроенные реализации для C # / VB / JScript ... но я бы удивился, если бы это отвечало вашим потребностям ...

Другой вариант: С Expression вы можете использовать ToString() - это работает и с LambdaExpression, так как это просто потомок.

...