【问题标题】:Construct AndAlso/OrElse LINQ expression with custom method使用自定义方法构造 AndAlso/OrElse LINQ 表达式
【发布时间】:2017-04-16 05:35:41
【问题描述】:

我正在尝试将自定义 MethodInfo 传递给 Expression.AndAlsoOrElse 工厂方法(分别用于 &&|| 运算符)。这些运算符使用短路,这很困难,但通常使用&| 运算符(以及truefalse 运算符)。但是,Expression.AndAlso/OrElse 的 MSDN 文档没有提及 true 或 false 运算符。

为了测试,我声明了一个在两个整数上使用普通& 运算符的方法:

public static int And(int a, int b) {
    return a & b;
}

请注意,返回类型必须是 int 而不是 bool 以避免异常。
然后我构造表达式:

var expr = Expression.AndAlso(
    Expression.Constant(0),
    Expression.Constant(5),
    new Func<int, int, int>(And).Method
);

这会导致异常:

运算符“AndAlso”的用户定义运算符方法“And”必须具有关联的布尔 True 和 False 运算符。

奇怪的是,如果我使用具有 truefalse 运算符的自定义结构,也会引发错误。如果结构重载&amp; 运算符并且我传入该重载,我可以避免它,但如果我传入不同的方法则不会。不过,其他非短路运算符使用自定义方法。

问题是我不知道如何传递 truefalse 运算符的方法。我首先认为我可以将它们组合为委托,但不同的方法具有不兼容的签名。有没有办法把这些方法传入?


大局

我正在构建一个用于解释表达式的系统,以支持提前编译。它支持对 AndAlso/OrElse 运算符使用自定义方法,目前通过采用自定义 Func&lt;InterpretedExpression, InterpretedExpression, object&gt; (当表达式被解释而不是编译时起作用)。如果它导致问题(这可能是由于它无法访问 truefalse 方法),则可以轻松更改此设置。


注意:我正在使用 Visual Studio 的 C# Interactive 窗口进行测试,但最终需要支持 .NET 3.5(尽管有关较新版本的信息仍然有用且值得赞赏)。

【问题讨论】:

    标签: c# .net linq expression-trees


    【解决方案1】:

    问题是我不知道如何传递真假运算符的方法。我首先认为我可以将它们组合为委托,但不同的方法具有不兼容的签名。有没有办法把这些方法传入?

    简短的回答是不,你不能。

    查看reference source implementation(不幸的是,它确实应该在文档中),看起来传递的方法具有以下约束:

    (1) 它应该是一个static 非泛型 带有签名的方法

    static T Method(T arg0, T arg1);
    

    其中T 不能是开放的泛型类型

    (2) 方法的声明类型必须定义运算符truefalse

    由于运算符truefalse 要求参数类型与声明类型相同,这结合(1)确实限制了类/结构T 声明静态方法和true 的使用和false 运营商。

    换句话说,一种具有按位 &amp; / | 运算符语义的方法,而不会实际重载这些运算符。

    所以它只能用于这样的类型:

    public struct IntWrapper
    {
        public readonly int Value;
        public IntWrapper(int value) { Value = value; }
        public static IntWrapper And(IntWrapper a, IntWrapper b) { return new IntWrapper(a.Value & b.Value); }
        public static bool operator true(IntWrapper x) { return x.Value != 0; }
        public static bool operator false(IntWrapper x) { return x.Value == 0; }
    }
    

    有用法:

    var expr = Expression.AndAlso(
        Expression.Constant(new IntWrapper(0)),
        Expression.Constant(new IntWrapper(5)),
        new Func<IntWrapper, IntWrapper, IntWrapper>(IntWrapper.And).Method
    );
    

    我猜这限制了你所追求的更一般的用法。

    【讨论】:

      猜你喜欢
      • 2012-03-03
      • 1970-01-01
      • 2011-03-15
      • 2022-01-19
      • 1970-01-01
      • 1970-01-01
      • 2023-03-20
      • 1970-01-01
      • 2023-03-08
      相关资源
      最近更新 更多