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

标签 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)
    {
    }
}

最佳答案

我不确定它在您的上下文中是否有意义,但是您可以解决将 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()();
    }

我已经反射(reflect)了 System.Core.dll 并且 Parameter 类不搜索任何重载运算符,如下所示:

    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

关于c# - 如何构建表达式以从基类调用相等运算符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37516935/

相关文章:

c# - 将字符串转换为可为空的日期时间

c# - 基类中的模板方法有什么用?

c# - 有什么方法可以在显示上下文菜单之前获取它的宽度?

c# - First/FirstOrDefault 没有像我预期的那样工作

c# - 从列表中删除相似条目

c# - headless chrome 无法像宣传的那样工作

c# - 如何在 C# 中使用 SQL 查询从 SQL 数据库中获取表的所有行

c# - Asp.net linq 查询

c# - 表达式树中的 ArrayAccess 与 ArrayIndex

c# - 如何使用 Entity Framework 和 Asp.Net 为 CRUD 操作编写 Linq 查询?