Estoy intentando anular el operador de igualdad (==) en C# para manejar la comparación de cualquier tipo un tipo personalizado (el tipo personalizado es realmente un contenedor/caja alrededor de nulo).Linq and the Equality Operator: Expresión del tipo 'System.Int32' no se puede usar para el parámetro de tipo 'System.Object'
así que tengo esto:
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;
}
...
}
Ahora bien, si hago una llamada como:
Nothing n = new Nothing();
bool equal = (10 == n);
Funciona perfectamente bien. Sin embargo, si trato de hacer esto mismo a través de un LINQ árbol de expresión:
exp = Expression.Equal(
Expression.Constant(10),
Expression.Constant(new Nothing(), typeof(Nothing))
);
Se inicia la excepción:
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)
¿Alguna idea de por qué el sistema base puede convertir Int32 al objeto, pero LINQ no puede, o cómo puedo arreglar esto?
Esta cosa entera se quedó porque LINQ también no se puede comparar a Int32 objeto en primer lugar:
exp = Expression.Equal(
Expression.Constant(10),
Expression.Constant(null)
);
lanza una excepción que indica que no hay ningún operador de comparación para "System.Int32" y "Sistema. Objeto".
seguimiento rápida:
La siguiente hacer el trabajo sin problemas:
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)
);
Así fundición específicamente todo lo que objetar. Entonces, ¿Linq simplemente no maneja la herencia internamente? Eso es bastante molesto ...
Seguimiento # 2:
También he intentado usar un método de comparación de encargo:
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;
}
Esto también se produce una excepción:
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)
Pero volviendo a enviar todo directamente a las obras objetadas:
exp = Expression.Equal(
Expression.Constant(10, typeof(object)),
Expression.Constant(null, typeof(object)),
false,
this.GetType().GetMethod("ValueEquals", BindingFlags.Public | BindingFlags.Static)
);
Así que supongo que tengo mi solución alternativa ... enviar todo para objetar y usar un método de comparación personalizado. Todavía estoy sorprendido de que Linq no haga la conversión automáticamente como lo hace C# normal.
"Entonces, ¿LINQ simplemente no maneja internamente la herencia?Eso es bastante molesto ... "Sí, es molesto, pero es por una buena razón. Las bibliotecas de árbol de expresiones funcionan con expresiones de C# y VB, y, para el caso, cualquier otro lenguaje que tenga ese tipo de expresiones. preparamos las reglas de conversión de C# en el código que manejaba la resolución de igualdad, entonces podríamos estar haciendo lo incorrecto con las expresiones que venían de VB. Por lo tanto, no hacemos ninguna de las dos: se requiere pasar expresiones no ambiguas para que la resolución sea lenguaje -agnostic. –
(se ha añadido el pensamiento a tu comentario) –
¡Bueno, no obtendrás una mejor autoridad sobre el tema que Eric Lippert! –