Я пытаюсь переопределить оператор равенства (==) в C# для обработки сравнения любого типа с пользовательский тип (пользовательский тип действительно обертка/поле вокруг нуля).Linq и оператор равенства: выражение типа «System.Int32» не может использоваться для параметра типа «System.Object»
Так у меня есть это:
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 в объект, но Linq не может, или как я могу это исправить?
Это все дело смотрел, потому что Linq также не может сравнить Int32 на объект в первую очередь:
exp = Expression.Equal(
Expression.Constant(10),
Expression.Constant(null)
);
Выдает исключение о том, что не существует оператор сравнения для «System.Int32» и «системы. Объект».
Быстрый Followup:
Следующая работают без проблем:
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 просто не обрабатывает наследование внутри? То очень раздражает ...
Followup # 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#.
«Так же Linq просто не справиться с наследования внутри? Thats очень раздражает ...» Да, это раздражает, но это по уважительной причине. Библиотеки дерева выражений работают с выражениями как с C#, так и с VB, и, если на то пошло, на любом другом языке, который имеет такие выражения. Если мы исправили правила преобразования C# в код, который обрабатывал разрешение равенства, то мы могли бы сделать неправильную вещь для выражений, которые пришли из VB. Таким образом, мы не делаем этого - вы должны передавать однозначные выражения, так что разрешение является языковым агностиком. –
(добавлено запомнилось вашим комментарием) –
Ну, вы не получите лучшего авторитета на эту тему, чем Эрик Липперт! –