Sto provando a sovrascrivere l'operatore di uguaglianza (==) in C# per gestire il confronto di qualsiasi tipo in un tipo personalizzato (il tipo personalizzato è in realtà un wrapper/box attorno a null).Linq e l'operatore di uguaglianza: espressione del tipo 'System.Int32' non può essere utilizzata per parametro di tipo 'System.Object'
Così ho questo:
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;
}
...
}
Ora, se faccio una chiamata del tipo:
Nothing n = new Nothing();
bool equal = (10 == n);
Funziona perfettamente bene. Tuttavia, se cerco di fare la stessa cosa attraverso un'espressione albero Linq:
exp = Expression.Equal(
Expression.Constant(10),
Expression.Constant(new Nothing(), typeof(Nothing))
);
Esso genera l'eccezione:
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)
Delle idee su perché il sistema di base in grado di convertire Int32 di opporsi, ma Linq non può, o come posso risolvere questo?
Questa intera faccenda fissò perché Linq, inoltre, non si può paragonare Int32 per oggetto, in primo luogo:
exp = Expression.Equal(
Expression.Constant(10),
Expression.Constant(null)
);
genera un'eccezione che indica che non v'è alcun operatore di confronto per "System.Int32" e "Sistema. Oggetto".
followup rapida:
Il seguente fare il lavoro senza problema:
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)
);
Così specificamente colata di tutto per opporsi. Quindi Linq non gestisce l'ereditarietà internamente? Quello è abbastanza fastidioso ...
Followup # 2:
Ho anche provato ad utilizzare un metodo di confronto personalizzato:
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;
}
Questo getta anche un'eccezione:
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)
Ma di nuovo tutto direttamente su opere oggetto:
exp = Expression.Equal(
Expression.Constant(10, typeof(object)),
Expression.Constant(null, typeof(object)),
false,
this.GetType().GetMethod("ValueEquals", BindingFlags.Public | BindingFlags.Static)
);
Quindi penso di avere la mia soluzione alternativa ... gettare tutto su oggetti e utilizzare un metodo di confronto personalizzato. Sono ancora sorpreso che Linq non esegua la conversione automaticamente come fa il normale C#.
"Quindi Linq non gestisce l'ereditarietà internamente?Questo è piuttosto fastidioso ... "Sì, è fastidioso, ma è per una buona ragione: le librerie ad albero delle espressioni funzionano con espressioni sia di C# che di VB e, se è per questo, qualsiasi altra lingua che abbia quel tipo di espressioni. abbiamo infornato le regole di conversione C# nel codice che gestiva l'uguaglianza risolvente, quindi potremmo fare la cosa sbagliata per le espressioni provenienti da VB. Quindi non ne facciamo nessuna - è necessario passare espressioni non ambigue, in modo che la risoluzione sia la lingua -agnostico –
(aggiunto pensato per il tuo commento) –
Beh, non si otterrà una migliore autorità in materia di Eric Lippert! –