Ich versuche, den Gleichheitsoperator (==) in C# zu überschreiben, um einen beliebigen Typ mit einem benutzerdefinierten Typ zu vergleichen (der benutzerdefinierte Typ ist wirklich ein Wrapper/Box um null).
Also habe ich das hier:
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;
}
...
}
Wenn ich nun einen Anruf tätige wie:
Nothing n = new Nothing();
bool equal = (10 == n);
Es funktioniert einwandfrei. Wenn ich jedoch versuche, das Gleiche über einen Linq-Ausdrucksbaum zu tun:
exp = Expression.Equal(
Expression.Constant(10),
Expression.Constant(new Nothing(), typeof(Nothing))
);
Er löst die Ausnahme aus:
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)
Irgendwelche Ideen, warum das Basissystem Int32 in Object konvertieren kann, aber Linq kann nicht, oder wie ich dies beheben kann?
Diese ganze Sache starrte, weil Linq auch nicht Int32 zu Object in erster Linie vergleichen kann:
exp = Expression.Equal(
Expression.Constant(10),
Expression.Constant(null)
);
Wirft eine Ausnahme, die besagt, dass es keinen Vergleichsoperator für "System.Int32" und "System.Object" gibt.
Kurze Nachbereitung:
Die folgenden funktionieren ohne Probleme:
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)
);
Also gezielt alles auf Objekt werfen. Behandelt Linq die Vererbung also einfach nicht intern? Das ist ziemlich ärgerlich...
Follow-up #2:
Ich habe auch versucht, eine benutzerdefinierte Vergleichsmethode zu verwenden:
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;
}
Auch hier wird eine Ausnahme ausgelöst:
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)
Aber auch hier funktioniert alles direkt als Objekt:
exp = Expression.Equal(
Expression.Constant(10, typeof(object)),
Expression.Constant(null, typeof(object)),
false,
this.GetType().GetMethod("ValueEquals", BindingFlags.Public | BindingFlags.Static)
);
Also ich denke, ich habe meine Abhilfe ... alles zu Objekt und verwenden Sie eine benutzerdefinierte Vergleichsmethode. Ich bin immer noch überrascht Linq tut nicht die Konvertierung automatisch als normale C# tut.