10

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#のように自動的に変換を行わないことに、私はまだ驚いています。

4

2 に答える 2

9

nullの何が問題になっていますか?行方不明のintvsnullについて、試してみてくださいint?

exp = Expression.Equal(
    Expression.Constant(10, typeof(int?)), 
    Expression.Constant(null, typeof(int?))
);
于 2009-05-08T14:51:50.293 に答える
0

null許容型を確認するには、この記事を参照してください。

http://msdn.microsoft.com/en-us/library/ms366789.aspx

于 2014-05-30T23:22:06.807 に答える