C#の等式(==)演算子をオーバーライドして、任意の型とカスタム型の比較を処理しようとしています(カスタム型は実際にはnullのラッパー/ボックスです)。
だから私はこれを持っています:
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#のように自動的に変換を行わないことに、私はまだ驚いています。