【问题标题】:Iterate over Each Argument Between && or || in an Expressions<Func<T,Bool>> Lambda Expression遍历 && 或 || 之间的每个参数在 Expressions<Func<T,Bool>> Lambda 表达式中
【发布时间】:2014-12-01 18:21:44
【问题描述】:

我想要一种操作类似于以下 LINQ-to-SQL Where 方法的方法。

 db.Where(r => r.Age == 42 && r.Name = "Joe");

我想实现:

Something something = Get<Something>()
    .FilterBy(x => x.PropOne == 123 && x.PropTwo == 456);

并使用如下方法;能够访问每个表达式参数的 Left.NameOperatorRight.Value 来执行工作。

public static T FilterBy<T>(this T something, Expression<Func<T, object>> e)
{
    // do work here
}

到目前为止,我可以在不使用 && 或 || 的情况下解析像 x =&gt; x.PropOne == 123 这样的单个条件使用下面的。

public static T FilterBy<T>(this T something, Expression<Func<T, object>> e)
{
    BinaryExpression binaryExpression = 
        (BinaryExpression)((UnaryExpression)e.Body).Operand;

    string left = ((MemberExpression)binaryExpression.Left).Member.Name;
    string right = binaryExpression
        .Right.GetType().GetProperty("Value")
        .GetValue(binaryExpression.Right).ToString();

    ExpressionType @operator = binaryExpression.NodeType;
    return (T)Convert.ChangeType(something, typeof(T));
}

当表达式的一部分与&amp;&amp;|| 结合时,如何访问每个表达式参数?

【问题讨论】:

  • 问题在哪里?
  • @MarcinJuraszek 我想知道如何从方法中访问每个表达式参数(使用示例实现)。
  • 表达式参数?抱歉,还是没看懂。也许其他人会有更多的运气。
  • @MarcinJuraszek 我想分别从FilterBy&lt;T&gt;() 内部访问x.PropOne == 123x.PropTwo == 456。抱歉,如果仍然不清楚。我想要一个与 LINQ 的 Where 方法类似的方法。
  • @SBPhoenix - 请检查我的编辑是否符合您的问题 - 尝试内联您的 cmets。

标签: c# generics lambda expression func


【解决方案1】:

示例代码

这里是一个如何获取&amp;&amp;的例子:

public static class FilterExtension
{
    public class Condition
    {
        public string Name { get; set; }
        public string Value { get; set; }
        public string Operator { get; set; }
    }

    public static T FilterBy<T>(this T something, Expression<Func<T, object>> e)
    {
        var conditions = new List<Condition>();
        BinaryExpression binaryExpression =
       (BinaryExpression)((UnaryExpression)e.Body).Operand;
        CheckConditions(conditions, binaryExpression);
        return (T)Convert.ChangeType(test, typeof(T));
    }

    private static void CheckConditions(List<Condition> conditions, BinaryExpression binaryExpression)
    {
        if (binaryExpression.NodeType == ExpressionType.AndAlso)
        {
            CheckConditions(conditions, binaryExpression.Left as BinaryExpression);
            CheckConditions(conditions, binaryExpression.Right as BinaryExpression);
        }
        else
        {
            conditions.Add(GetCondition(binaryExpression));
        }
    }

    private static Condition GetCondition(BinaryExpression binaryExpression)
    {
        var condition = new Condition();
        condition.Name = ((MemberExpression)binaryExpression.Left).Member.Name;
        condition.Value = binaryExpression
            .Right.GetType().GetProperty("Value")
            .GetValue(binaryExpression.Right, null).ToString();
        condition.Operator = binaryExpression.NodeType.ToString();
        return condition;
    }
}

显然&amp;&amp; 的代码不完整;你应该有一个想法。

另外,我注意到你传入了一个T 类型的对象。如果它像 Linq-To-SQL where 一样工作,它可能应该是某种列表或可枚举的。

示例: public static T FilterBy&lt;T&gt;(this List&lt;T&gt; something, Expression&lt;Func&lt;T, object&gt;&gt; e)

注意事项

请注意,可以将许多不同的表达式传递到此方法中,这些表达式将编译但会破坏您的方法。

Something something = Get&lt;Something&gt;().FilterBy(x =&gt; 123 == x.PropOne);

Something something = Get&lt;Something&gt;().FilterBy(x =&gt; x.Method() == 123);

Something something = Get&lt;Something&gt;().FilterBy(x =&gt; (x.PropOne == 123 || x.PropOne == 34) &amp;&amp; x.PropTwo == 456 );

确保验证表达式是您期望的类型。

【讨论】:

  • 这当然有帮助,非常感谢您的考虑和示例。我将如何迭代每个&amp;&amp;?我会使用foreach 循环吗?如果是,您是否知道一个示例?
  • 我改变了我的例子来展示一个使用递归的基本实现。我还假设您想要捕获表达式的值,所以我将它们存储在一个列表中。这似乎是您要找的东西吗?
  • 这正是我正在寻找的,除了我似乎收到了 CheckConditions(conditions, binaryExpression.Left)CheckConditions(conditions, binaryExpression.Right) 的编译错误,指出 CheckConditions 是一种未知方法?再次感谢您的所有帮助!
  • 这正是我所需要的完全,它就像一个魅力! SO 非常感谢您的帮助。我一直在为此绞尽脑汁,因为我对一般表达方式不熟悉。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-02
  • 1970-01-01
相关资源
最近更新 更多