Linq Expressions параметризация уже существующего Expression

163
29 ноября 2018, 07:20

Пытаюсь преобразовать один Expression<Func<double, double>> в другой, однако при попытке компиляции полученного выражения, появляется ошибка

System.InvalidOperationException : На переменную "z" типа "System.Double" имеется
ссылка из области "", но она не определена.

Если я правильно понимаю, то эту проблему можно решить заменив в все ParameterExpression в исходном Expression на один и тот же( т.к у меня функция от одной переменной). Подскажите существует ли способ это сделать?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
namespace Reflection.Differentiation
{
    public static class Algebra
    {
        private static Dictionary<ExpressionType, Func<Expression, Expression>> diffFuncs;
        private static void InitializeExprDiffFuncs()
        {
            diffFuncs = new Dictionary<ExpressionType, Func<Expression, Expression>>
            {
                [ExpressionType.Multiply] = (expr) =>
                {
                    var e = (BinaryExpression)expr;
                    if (e.Left is ConstantExpression || e.Right is ConstantExpression)
                    {
                        var constExpr = (e.Left is ConstantExpression) ? e.Left : e.Right;
                        var otherExpr = (e.Left is ConstantExpression) ? e.Right : e.Left;
                        return Expression.Multiply((ConstantExpression)constExpr, diffFuncs[otherExpr.NodeType](otherExpr));
                    }
                    else
                    {
                        return Expression.Add(
                            Expression.Multiply(e.Left, diffFuncs[e.Right.NodeType](e.Right)),
                            Expression.Multiply(e.Right, diffFuncs[e.Left.NodeType](e.Left))
                            );
                    }
                },
                [ExpressionType.Add] = (expr) =>
                {
                    var e = (BinaryExpression)expr;
                    return Expression.Add(diffFuncs[e.Left.NodeType](e.Left), diffFuncs[e.Right.NodeType](e.Right));
                },
                [ExpressionType.Call] = (expr) =>
                {
                    var e = (MethodCallExpression)expr;
                    if (e.Method.Name == "Sin")
                    {
                        return Expression.Multiply(
                            Expression.Call(null, typeof(Math).GetMethod("Cos", new[] { typeof(double) }), e.Arguments[0]),
                            diffFuncs[e.Arguments[0].NodeType](e.Arguments[0])
                            );
                    }
                    if (e.Method.Name == "Cos")
                    {
                        return Expression.Multiply(
                            Expression.Multiply(
                                Expression.Call(null, typeof(Math).GetMethod("Sin", new[] { typeof(double) }), e.Arguments[0]),
                                Expression.Constant((double)-1)
                                ),
                            diffFuncs[e.Arguments[0].NodeType](e.Arguments[0])
                            );
                    }
                    throw new ArgumentException(expr.ToString() + "have unexpexted call");
                },
                [ExpressionType.Constant] = (expr) => Expression.Constant((double)0),
                [ExpressionType.Parameter] = (expr) => Expression.Constant((double)1)
            };
        }
        static Algebra()
        {
            InitializeExprDiffFuncs();
        }
        public static Expression<Func<double, double>> Differentiate(Expression<Func<double, double>> funcExpr)
        {
            var parameter = Expression.Parameter(typeof(double), "z");
            var expr = diffFuncs[funcExpr.Body.NodeType](funcExpr.Body);
            var lambda = Expression.Lambda<Func<double, double>>(expr, parameter);
            return lambda;
        }
    }
}
Answer 1

Дело в том, что после всех ваших преобразований в вашем выражении все еще остается переменная z от изначальной лямбды, которая не указана в списке параметров. Вместо нее вы создаете новую переменную, которая хоть и имеет то же самое имя, но нигде в выражении не используется.

Когда вы трансформируете выражение сохраняя переменные в нем - нужно копировать их из старой лямбды в новую:

return Expression.Lambda<Func<double, double>>(expr, funcExpr.Parameters);
READ ALSO
Использование Cookie при работе с HtmlAgilityPack

Использование Cookie при работе с HtmlAgilityPack

С помощью SimpleBrowser заполняю поля логина и пароля и имитирую нажатие кнопки, после чего происходит вход на сайтДалее из объекта извлекаю файлы...

153
Выполнить void в get/set

Выполнить void в get/set

Посоветуйте как без создания дополнительных переменных реализовать такое:

158
Не видит функцию С# Unity

Не видит функцию С# Unity

Я создал скрипт C# в котором есть несколько функций и функция ChooseResolution()Прицепил его на пустой объект UIManager, который засунул в поле для объектов...

165
Как подключится к серверу WoW? [C#] [закрыт]

Как подключится к серверу WoW? [C#] [закрыт]

Вообщем интересует ответ на вопрос , который уже озвучен в заголовке тредаВозможно есть уже готовая реализация или же если подскажите в какую...

152