如何构建表达式以从基类调用相等运算符?

时间:2016-05-30 02:43:01

标签: c# linq

如果有问题的类型实现operator ==(),那么我可以轻松地构建一个表达式来调用它。但是如果在基类中定义了运算符,它就不起作用 - 看看有三个断言通过但是一个失败了。

有没有正确的方法呢?

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
        Assert.IsTrue(new A(42) == new A(42)); // PASS
        Assert.IsTrue(ExecuteOperatorEqual(new A(42), new A(42))); // PASS
        Assert.IsTrue(new B(42) == new B(42)); // PASS
        Assert.IsTrue(ExecuteOperatorEqual(new B(42), new B(42))); // FAIL
    }

    static bool ExecuteOperatorEqual<T>(T item1, T item2)
    {
        var expression = Expression.Lambda<Func<bool>>(
            Expression.Equal(
                Expression.Constant(item1),
                Expression.Constant(item2)));
        return expression.Compile()();
    }
}

class A
{
    private readonly int _value;

    public A(int value)
    {
        _value = value;
    }

    public static bool operator ==(A left, A right) => left._value == right._value;

    public static bool operator !=(A left, A right) => left._value != right._value;
}

class B : A
{
    public B(int value) : base(value)
    {
    }
}

1 个答案:

答案 0 :(得分:1)

我不确定它在您的上下文中是否有意义,但您可以解决将MethodInfo传递给您的问题Expression.Equal

    static bool ExecuteOperatorEqual<T>(T item1, T item2)
    {
        BindingFlags bindingAttr = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;
        var equalityMethod = typeof(T).GetMethod("op_Equality", bindingAttr, null, new Type[] { typeof(T), typeof(T) }, null);

        var expression = Expression.Lambda<Func<bool>>(
            Expression.Equal(
                Expression.Constant(item1),
                Expression.Constant(item2),
                false,
                equalityMethod
                ));
        return expression.Compile()();
    }

我已反映System.Core.dllParameter类未搜索任何重载运算符,如下所示:

    private static MethodInfo GetUserDefinedBinaryOperator(ExpressionType binaryType, Type leftType, Type rightType, string name)
    {
        Type[] types = new Type[]
        {
            leftType,
            rightType
        };
        Type nonNullableType = leftType.GetNonNullableType();
        Type nonNullableType2 = rightType.GetNonNullableType();
        BindingFlags bindingAttr = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
        MethodInfo methodInfo = nonNullableType.GetMethodValidated(name, bindingAttr, null, types, null);
        if (methodInfo == null && !TypeUtils.AreEquivalent(leftType, rightType))
        {
            methodInfo = nonNullableType2.GetMethodValidated(name, bindingAttr, null, types, null);
        }
        if (Expression.IsLiftingConditionalLogicalOperator(leftType, rightType, methodInfo, binaryType))
        {
            methodInfo = Expression.GetUserDefinedBinaryOperator(binaryType, nonNullableType, nonNullableType2, name);
        }
        return methodInfo;
    }

添加BindingFlags.FlattenHierarchy会找到相等运算符。他们必须有理由不将其添加到.Net