我该如何撰写Linq的前pressions?即Func键<精通<函数功能:其中,X,Y>>中精通< Func键< Y,Z>>中精通< Func键< X,Z>>> [英] How do I compose Linq Expressions? ie Func<Exp<Func<X, Y>>, Exp<Func<Y, Z>>, Exp<Func<X, Z>>>

查看:200
本文介绍了我该如何撰写Linq的前pressions?即Func键<精通<函数功能:其中,X,Y>>中精通< Func键< Y,Z>>中精通< Func键< X,Z>>>的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建一个验证器; T> 类。我试图实现的LINQ我的验证,以便能够即使构成使用LINQ查询EX pressions和验证的最终结果的根本的SelectMany 扩展方法值的变化。

I'm creating a Validator<T> class. I'm attempting to implement the Linq SelectMany extension methods for my validator to be able to compose expressions using a Linq query and validate the final result even when the underlying values change.

下面的测试code说明我的意图。

The following test code demonstrates my intent.

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防爆pressions 这说明我如何组合两个 Func键&LT; T,布尔&GT; 的一起使用 EX pression,但我需要能够撰写功能一起更,好,实用的方式。

I've seen the following question How do I compose existing Linq Expressions which shows me how to compose two Func<T, bool>'s together using an And expression, but I need to be able to compose functions together in a more, well, functional way.

我有,例如,下面的两个前pressions:

I have, for example, the following two expressions:

public Expression<Func<T>> ValueExpression { get; private set; }
public Expression<Func<T, bool>> ValidationExpression { get; private set; }

我想创建一个新的EX pression是这样的:

I wish to create a new expression like this:

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

更简洁地说我试图创建这些功能:

More succinctly I'm trying to create these functions:

// Specific case
Func<Expression<Func<T>>, Expression<Func<T, bool>>, Expression<Func<bool>>>
// General case
Func<Expression<Func<X, Y>>, Expression<Func<Y, Z>>, Expression<Func<X, Z>>>

一般情况下,功能可以被修改以接受不同数量的通用参数按需要来撰写任何功能。

The general case function can be modified to accept different numbers of generic arguments as needed to compose any function.

我搜索堆栈溢出(当然)和网络,但都没有能够解决这个问题的一个例子。

I've searched Stack Overflow (of course) and the web, but haven't an example that solves this issue.

我的code为验证器; T&GT; 类是低​​于

My code for the Validator<T> class is below.

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

    public Expression<Func<T>> ValueExpression { get; private set; }
    public Expression<Func<T, bool>> ValidationExpression { get; private set; }

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

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

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

我的的SelectMany 扩展包含负载令人讨厌 .Compile()调用(),我想摆脱的。

My SelectMany extensions contain loads of yucky .Compile().Invoke() which I want to get rid of.

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

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

在此先感谢!

Thanks in advance!

推荐答案

Haskell的函数组合的操作符

The equivalent of Haskell's function composition operator

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

将在C#中可能会像

would in C# probably be something like

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

这是你要找的是什么?

Is this what you're looking for?

例如:

Compose<int, int, string>(y => y.ToString(), x => x + 1).Compile()(10); // "11"

这篇关于我该如何撰写Linq的前pressions?即Func键&LT;精通&LT;函数功能:其中,X,Y&GT;&gt;中精通&LT; Func键&LT; Y,Z&GT;&gt;中精通&LT; Func键&LT; X,Z&GT;&GT;&GT;的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆