I'm trying to pass in a custom MethodInfo
to the Expression.AndAlso
and OrElse
factory methods (which are for the &&
and ||
operators, respectively). These operators use short circuiting, which makes this difficult, but normally the &
and |
operators (along with the true
and false
operators) are used. However, the MSDN documentation for Expression.AndAlso/OrElse
doesn't mention the true or false operators.
For testing, I've declared a method that uses a normal &
operator on two ints:
public static int And(int a, int b) {
return a & b;
}
Note that the return type must be int
rather than bool
to avoid an exception.
I then construct the expression:
var expr = Expression.AndAlso(
Expression.Constant(0),
Expression.Constant(5),
new Func<int, int, int>(And).Method
);
This results in an exception:
The user-defined operator method 'And' for operator 'AndAlso' must have associated boolean True and False operators.
Strangely, the error is also thrown if I use a custom struct that has the true
and false
operators. I can avoid it if the struct overloads the &
operator and I pass in that overload, but not if I pass in a different method. Other non-short-circuiting operators work with custom methods though.
The problem is that I don't know how to pass methods for the true
and false
operators in. I first thought I could maybe combine them as delegates, but the different methods have incompatible signatures. Is there any way to pass these methods in?
The bigger picture
I'm building a system for interpreting expressions to support ahead-of-time compilation. It supports using a custom method for the AndAlso/OrElse operators, currently by taking a custom Func<InterpretedExpression, InterpretedExpression, object>
(which works as the expressions are interpreted rather than compiled). This could easily be changed if it causes problems (which would be due to it not having accessible true
and false
methods).
Note: I'm using Visual Studio's C# Interactive window for testing, but ultimately need to support .NET 3.5 (though information for newer versions is still helpful and appreciated).
The problem is that I don't know how to pass methods for the true and false operators in. I first thought I could maybe combine them as delegates, but the different methods have incompatible signatures. Is there any way to pass these methods in?
The short answer is no, you can't.
Looking at the reference source implementation (unfortunately, it should really be in the documentation), looks like the passed method has the following constraints:
(1) It should be a static
non generic method with signature
static T Method(T arg0, T arg1);
where T
cannot be an open generic type.
(2) The declaring type of the method must have operators true
and false
defined.
Since operators true
and false
require the argument type to be the same as the declaring type, this combined with (1) really constraints the usage to class/struct T
declaring the static method and true
and false
operators.
In other words, a method with bitwise &
/ |
operator semantics without actually overloading those operators.
So it can be used only for types like this:
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; }
}
with usage:
var expr = Expression.AndAlso(
Expression.Constant(new IntWrapper(0)),
Expression.Constant(new IntWrapper(5)),
new Func<IntWrapper, IntWrapper, IntWrapper>(IntWrapper.And).Method
);
This I guess limits more general usage you are after.