Linq и оператор равенства: выражение типа «System.Int32» нельзя использовать для параметра типа «System.Object». - PullRequest
10 голосов
/ 08 мая 2009

Я пытаюсь переопределить оператор равенства (==) в C #, чтобы выполнить сравнение любого типа с пользовательским типом (пользовательский тип действительно является оберткой / рамкой вокруг нуля).

Итак, у меня есть это:

internal sealed class Nothing
{
    public override bool Equals(object obj)
    {
        if (obj == null || obj is Nothing)
            return true;
        else
            return false;
    }

    public static bool operator ==(object x, Nothing y)
    {
        if ((x == null || x is Nothing) && (y == null || y is Nothing))
            return true;
        return false;
    }
   ...
}

Теперь, если я позвоню как:

Nothing n = new Nothing();
bool equal = (10 == n);

Работает отлично. Однако, если я попытаюсь сделать то же самое через дерево выражений Linq:

exp = Expression.Equal(
    Expression.Constant(10), 
    Expression.Constant(new Nothing(), typeof(Nothing))
);

Выдает исключение:

System.ArgumentException : Expression of type 'System.Int32' cannot be used for parameter of type 'System.Object' of method 'Boolean op_Equality(System.Object, PARTSFinder.Rules.Runtime.RulesNothing)'
    at System.Linq.Expressions.Expression.ValidateArgumentTypes(MethodInfo method, ReadOnlyCollection`1& arguments)
    at System.Linq.Expressions.Expression.ValidateCallArgs(Expression instance, MethodInfo method, ReadOnlyCollection`1& arguments)
    at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, IEnumerable`1 arguments)
    at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, Expression[] arguments)
    at System.Linq.Expressions.ExpressionCompiler.GenerateBinaryMethod(ILGenerator gen, BinaryExpression b, StackType ask)

Любые идеи о том, почему базовая система может конвертировать Int32 в Object, но Linq не может, или как я могу это исправить?

Все это выглядело так, потому что Linq также не может сравнивать Int32 с Object:

exp = Expression.Equal(
    Expression.Constant(10), 
    Expression.Constant(null)
);

Выдает исключение, утверждающее, что нет оператора сравнения для "System.Int32" и "System.Object".


Быстрое наблюдение:

Следующее работает без проблем:

exp = Expression.Equal(
    Expression.Constant(10, typeof(object)), 
    Expression.Constant(new Nothing(), typeof(Nothing))
);

exp = Expression.Equal(
    Expression.Constant(10, typeof(object)), 
    Expression.Constant(null)
);

Так что конкретно приведем все к объекту. Так разве Linq просто не обрабатывает наследование внутренне? Это довольно раздражает ...


Продолжение № 2:

Я также пытался использовать собственный метод сравнения:

exp = Expression.Equal(
    Expression.Constant(10),
    Expression.Constant(null),
    false,
    this.GetType().GetMethod("ValueEquals", BindingFlags.Public | BindingFlags.Static)
);

    public static bool ValueEquals(object x, object y)
    {
        if (x == null && y == null)
            return true;
        if (x.GetType() != y.GetType())
            return false;
        return x == y;
    }

Это также вызывает исключение:

System.InvalidOperationException : The operands for operator 'Equal' do not match the parameters of method 'ValueEquals'.
    at System.Linq.Expressions.Expression.GetMethodBasedBinaryOperator(ExpressionType binaryType, Expression left, Expression right, MethodInfo method, Boolean liftToNull)

Но снова приведение всех непосредственно к объекту работает:

exp = Expression.Equal(
    Expression.Constant(10, typeof(object)),
    Expression.Constant(null, typeof(object)),
    false,
    this.GetType().GetMethod("ValueEquals", BindingFlags.Public | BindingFlags.Static)
);

Так что я думаю, у меня есть обходной путь ... приведите все к объекту и используйте собственный метод сравнения. Я все еще удивлен, что Linq не выполняет преобразование автоматически, как это делает обычный C #.

Ответы [ 2 ]

9 голосов
/ 08 мая 2009

Что не так с нулем? Пропустив int против null, попробуйте int?:

exp = Expression.Equal(
    Expression.Constant(10, typeof(int?)), 
    Expression.Constant(null, typeof(int?))
);
0 голосов
/ 31 мая 2014

Вы должны взглянуть на эту статью, чтобы проверить обнуляемый тип.

http://msdn.microsoft.com/en-us/library/ms366789.aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...