Как я составляю Выражения Linq? т.е. Func <Exp <Func <X, Y>>, Exp <Func <Y, Z>>, Exp <Func <X, Z>>>

Я создаю a Validator класс. Я пытаюсь реализовать Linq SelectMany дополнительные методы для моего блока проверки допустимости, чтобы смочь составить выражения с помощью Linq запрашивают и проверяют конечный результат, даже когда базовые значения изменяются.

Следующий тестовый код демонстрирует мое намерение.

var a = 2;
var b = 3;

var va = Validator.Create(() => a, n => n >= 0 && n < 5);
var vb = Validator.Create(() => b, n => n >= 0 && n < 5);

var vc = from ia in va
         from ib in vb
         select ia + ib;

Debug.Assert(vc.Value == a + b); //2 + 3
Debug.Assert(vc.Value == 5);

Debug.Assert(vc.IsValid == true);

a = 7;

Debug.Assert(vc.Value == a + b); //7 + 3
Debug.Assert(vc.Value == 10);

Debug.Assert(va.IsValid == false);
Debug.Assert(vb.IsValid == true);
Debug.Assert(vc.IsValid == false);

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

У меня есть, например, следующие два выражения:

public Expression> ValueExpression { get; private set; }
public Expression> ValidationExpression { get; private set; }

Я хочу создать новое выражение как это:

    public Expression> IsValidExpression
    {
        get
        {
            // TODO: Compose expressions rather than compile & invoke.
        }
    }

Более кратко я пытаюсь создать эти функции:

// Specific case
Func>, Expression>, Expression>>
// General case
Func>, Expression>, Expression>>

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

Я искал Переполнение стека (конечно), и сеть, но не имею примера, который решает эту проблему.

Мой код для Validator класс ниже.

public class Validator
{
    public Validator(Expression> valueFunc,
        Expression> validationFunc)
    {
        this.ValueExpression = valueFunc;
        this.ValidationExpression = validationFunc;
    }

    public Expression> ValueExpression { get; private set; }
    public Expression> ValidationExpression { get; private set; }

    public T Value { get { return this.ValueExpression.Compile().Invoke(); } }

    public bool IsValid { get { return this.IsValidExpression.Compile().Invoke(); } }

    public Expression> IsValidExpression
    {
        get
        {
            // TODO: Compose expressions.
        }
    }
}

Мой SelectMany расширения содержат загрузки yucky .Compile().Invoke() от которого я хочу избавиться.

public static Validator SelectMany(this Validator @this, Expression>> k)
{
    Expression> fvtv = @this.ValueExpression;
    Expression>> fvu = () => k.Compile().Invoke(fvtv.Compile().Invoke());
    Expression> fvuv = fvu.Compile().Invoke().ValueExpression;
    Expression> fvtiv = u => @this.ValidationExpression.Compile().Invoke(fvtv.Compile().Invoke());
    return fvuv.ToValidator(fvtiv);
}

public static Validator SelectMany(this Validator @this, Expression>> k, Expression> s)
{
    Expression>> fvu = () => @this.SelectMany(k);
    Expression> fvtv = @this.ValueExpression;
    Expression> fvuv = fvu.Compile().Invoke().ValueExpression;
    Expression> fvtiv = @this.ValidationExpression;
    Expression> fvuiv = u => fvu.Compile().Invoke().ValidationExpression.Compile().Invoke(u);
    Expression> fvv = () => s.Compile().Invoke(fvtv.Compile().Invoke(), fvuv.Compile().Invoke());
    Expression> fvviv = v => fvtiv.Compile().Invoke(fvtv.Compile().Invoke()) && fvuiv.Compile().Invoke(fvuv.Compile().Invoke());
    return fvv.ToValidator(fvviv);
}

Заранее спасибо!

14
задан Community 23 May 2017 в 12:10
поделиться

1 ответ

Эквивалент Haskell функции композиции operator

(.) :: (b->c) -> (a->b) -> (a->c)
f . g = \ x -> f (g x)

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

static Expression<Func<A, C>> Compose<A, B, C>(
    Expression<Func<B, C>> f,
    Expression<Func<A, B>> g)
{
    var x = Expression.Parameter(typeof(A));
    return Expression.Lambda<Func<A, C>>(
        Expression.Invoke(f, Expression.Invoke(g, x)), x);
}

ищите?

Пример:

Compose<int, int, string>(y => y.ToString(), x => x + 1).Compile()(10); // "11"
19
ответ дан 1 December 2019 в 07:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: