Scyldshefing Ответов: 3

Как избежать необходимости возвращать целое число при построении выражения?


Я пытаюсь построить движок правил, используя некоторые элементы отражения и System. Linq.Пространство имен выражений. Я пытаюсь построить выражение Lamdba в виде
Выражение.Лямбда - &ЛТ;изм&ЛТ;Т, инт&ГТ;&ГТ;(expressionToCompile, параметр).Компилировать();

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

Что я уже пробовал:

На данный момент мой код содержит следующий метод:

private static void CompileRuleDefinition<T>(RuleDefinition<T> ruleDefinition)
        {
            var parameter = Expression.Parameter(typeof(T));
            Expression expresion = BuildCompoundConditions(ruleDefinition, parameter);
            Expression expressionToCompile = null;
            Expression thenClause = BuildAssignExpression<T>(parameter, ruleDefinition.ThenAction);

            if (expresion != null)
            {
                if (ruleDefinition.ThenAction != null && ruleDefinition.ElseAction == null)
                {
                    expressionToCompile =
                        Expression.Block(
                            Expression.IfThen(
                                expresion,
                                thenClause),
                            Expression.Constant(42));
                }

                if (ruleDefinition.ThenAction != null && ruleDefinition.ElseAction != null)
                {
                    Expression elseClause = BuildAssignExpression<T>(parameter, ruleDefinition.ElseAction);
                    expressionToCompile =
                        Expression.Block(
                            Expression.IfThenElse(
                                expresion,
                                thenClause,
                                elseClause),
                            Expression.Constant(42));
                }

                if (expressionToCompile != null)
                {
                    ruleDefinition.CompiledExpression =
                        Expression.Lambda<Func<T, int>>(expressionToCompile, parameter).Compile();
                }
            }
        }


Мне не нравится использование команды :
Expression.Constant(42));
это ничего не делает в моем коде, а просто позволяет возвращать целое число. Типы, возвращаемые предложением "Then" и предложением "Else", могут варьироваться от" Void " (именно с этого началась моя проблема, поскольку действие может заключаться в вызове метода void в классе <t>) до int, bool и т. д.

То, что я ищу, - это решение, в котором мне не нужно иметь этот кусок избыточного кода.

(да, у кода действительно есть проблема, если ThenAction также NULL)

Philippe Mori

Вместо того чтобы пытаться Func<T, void>, что произойдет, если вы используете Action<T> вместо этого? Один Action по существу, это как Func без возвращаемого значения.

3 Ответов

Рейтинг:
2

OriginalGriff

Когда вы указываете Func, он имеет два параметра-T и TResult:

Func<T, TResult>

Таким образом, ваш код явно говорит:
Func<T, int>

Который объявляет, что функция должна возвращать целочисленное значение.
Вы не можете "избавиться" от возвращаемого типа: Делегат Func(T, TResult) (System)[^] потому что каждая функция должна иметь один тип (даже конструкторы имеют возвращаемый тип, но он неявен, а не явен в определении), хотя вы можете заменить его int с другим типом или даже с void - но я не пробовал возвращать пустоты при таких обстоятельствах. Это будет зависеть от остальной части кода, который вы написали, и я понятия не имею, как это выглядит!


Scyldshefing

Я не могу использовать void в качестве возвращаемого типа в лямбда-выражении (конечно, не так, как я это пробовал).

if (expressionToCompile != null)
{
ruleDefinition.CompiledExpression =
Выражение.Лямбда - &ЛТ;изм&ЛТ;Т, ничтоже&ГТ;&ГТ;(expressionToCompile, параметр).Компилировать();
}

получает следующее сообщение об ошибке:

Ключевое слово "void" не может быть использовано в этом контексте

Если я заменю int на object и удалю выражение.Постоянная строка в моем модульном тесте я получаю следующее исключение:

Имя Теста: TestIfThenElseCondition
Полное Имя Теста: UnitTestProject1.GivenIfThenElse.TestIfThenElseCondition
Источник теста: c:\VSSolution\RulesEngine\UnitTestProject1\GivenIfThenElse.cs : строка 17
Результат Теста: Не Удалось
Продолжительность Теста: 0: 00:00.0014237

Сообщение О Результате:
Метод испытания UnitTestProject1.GivenIfThenElse.TestIfThenElseCondition бросил исключение:
Система.ArgumentException: выражение типа 'System. Void' не может быть использовано для возвращаемого типа ' System.Объект'
Трассировка Стека Результат :
в системе.В LINQ.Выражения.Выражение.ValidateLambdaArgs(Type delegateType, Expression&body, ReadOnlyCollection`1 параметры)
в системе.В LINQ.Выражения.Выражение.Lambda[TDelegate](тело выражения, строковое имя, логический tailCall, параметры IEnumerable`1)
в системе.В LINQ.Выражения.Выражение.Lambda[TDelegate](тело выражения, логический tailCall, параметры IEnumerable`1)
в системе.В LINQ.Выражения.Выражение.Lambda[TDelegate](тело выражения, параметры ParameterExpression[] )
на свойства rulesengine.RulesHelper. CompileRuleDefinition[T](RuleDefinition`1 ruleDefinition) в c:\VSSolution\RulesEngine\RulesEngine\RulesHelper.cs:line 111
на свойства rulesengine.RulesHelper.CompileRuleSet[Т](правил`1 правил) в c:\VSSolution\RulesEngine\RulesEngine\RulesHelper.cs:line 71
в UnitTestProject1.GivenIfThenElse.TestIfThenElseCondition () in c:\VSSolution\RulesEngine\UnitTestProject1\GivenIfThenElse.cs:line 34

Scyldshefing

Я разместил код на GitHub @ https://github.com/Scyldshefing/RulesEngineII

Рейтинг:
0

Scyldshefing

Я получил предложение использовать Action вместо Func (по какой-то причине этот ответ не появляется). Я применил изменения,и все мои тесты прошли успешно - похоже, это исправление. Большое спасибо.


private static void CompileRuleDefinition<T>(RuleDefinition<T> ruleDefinition)
{
    var parameter = Expression.Parameter(typeof(T));
    Expression expresion = BuildCompoundConditions(ruleDefinition, parameter);
    Expression expressionToCompile = null;
    Expression thenClause = BuildAssignExpression<T>(parameter, ruleDefinition.ThenAction);

    if (expresion != null)
    {
        if (ruleDefinition.ThenAction != null && ruleDefinition.ElseAction == null)
        {
            expressionToCompile =
                Expression.Block(
                    Expression.IfThen(
                        expresion,
                        thenClause));
        }

        if (ruleDefinition.ThenAction != null && ruleDefinition.ElseAction != null)
        {
            Expression elseClause = BuildAssignExpression<T>(parameter, ruleDefinition.ElseAction);
            expressionToCompile =
                Expression.Block(
                    Expression.IfThenElse(
                        expresion,
                        thenClause,
                        elseClause));
        }

        if (expressionToCompile != null)
        {
            ruleDefinition.CompiledExpression =
                Expression.Lambda<Action<T>>(expressionToCompile, parameter).Compile();
        }
    }
}


Рейтинг:
0

Scyldshefing

Я еще больше усовершенствовал решение, удалив внешний блок исключений:

private static void CompileRuleDefinition<T>(RuleDefinition<T> ruleDefinition)
{
    var parameter = Expression.Parameter(typeof(T));
    Expression expresion = BuildCompoundConditions(ruleDefinition, parameter);
    Expression expressionToCompile = null;
    Expression thenClause = BuildAssignExpression<T>(parameter, ruleDefinition.ThenAction);

    if (expresion != null)
    {
        if (ruleDefinition.ThenAction != null && ruleDefinition.ElseAction == null)
        {
            expressionToCompile = Expression.IfThen(expresion, thenClause);
        }

        if (ruleDefinition.ThenAction != null && ruleDefinition.ElseAction != null)
        {
            Expression elseClause = BuildAssignExpression<T>(parameter, ruleDefinition.ElseAction);
            expressionToCompile =
                Expression.IfThenElse(
                        expresion,
                        thenClause,
                        elseClause);
        }

        if (expressionToCompile != null)
        {
            ruleDefinition.CompiledExpression =
                Expression.Lambda<Action<T>>(expressionToCompile, parameter).Compile();
        }
    }
}