8

非常に単純なコードから始めましょう。

decimal d = 2;

Console.WriteLine("d == 2 = {0}", d == 2);
Console.WriteLine("d == (decimal)2 = {0}", d == (decimal)2);
Console.WriteLine("d.Equals(2) = {0}", d.Equals(2));
Console.WriteLine("d.Equals((decimal)2) = {0}", d.Equals((decimal)2));

結果は 4xtrue です。では、変数dの型を10 進数に変更してみましょう。:

decimal? d = 2;

今回の結果はTrue、True、False、True になります。この状況の説明は非常に簡単です。Nullable<T>型の場合、 Equalsメソッドは次のように実装されます。

public override bool Equals(object other)
{
    if (!this.HasValue)
    {
        return (other == null);
    }
    if (other == null)
    {
        return false;
    }
    return this.value.Equals(other);
}

これに値があり、他のパラメーターが null でない場合、Decimal.Equals (オブジェクト値)が呼び出されます。Decimal.Equals(object value)メソッドはこのように機能し、パラメーターが10 進数でない場合、結果は常にfalseになります。

現在の実装は直感的ではないように思えます.Nullable<T>が開発者にEqualsメソッドの汎用バージョンを提供しないのはなぜだろうか.例えば:

public bool Equals(T other)
{
    if (!this.HasValue)
        return false;

    return this.value.Equals(other);
}

わざとやったのか、それとも手抜きなのか。

コメント 1:

明確にするための簡単なコメント。Nullable<T>には 2 つのEqualsメソッド、つまりpublic override bool Equals(object other)public bool Equals(T other)が必要であることを提案しました。

4

2 に答える 2

1

私はこれらの質問が好きですが、タイプを担当する設計チームのメンバーだけが実際に答えることができます. Value明らかな回避策は、 that isにアクセスし、 thatTの を使用するEqualsことです。

私の最善の推測は、特定の型に一般的にアクセスするために、おそらく allTを強制することです。これはコア値の型では機能しますが、他の .NET 構造体は必ずしもそのインターフェイスを実装するとは限らず、型は実装しません。IEquatable<T>Equals<T>enum

型チェック/キャストを介して行うことができると思いますが、これには、呼び出し元が単純に行うのとは対照的に、多くの手間がかかります: myNullable.GetValueOrDefault().Equals().

このタスクを実行するための拡張メソッドを作成して、ジェネリック引数を明示的に指定する必要があるメソッドを呼び出させることができます (そうしないと、コンパイラは以下を呼び出しますEquals(object):

class Program
{
    static void Main(string[] args)
    {
        double? d = null;

        Console.WriteLine(d.Equals<double>(0.0));

        d = 0.0;

        Console.WriteLine(d.Equals<double>(0.0));

        Console.Read();
    }
}

public static class NullableExtensions
{
    public static bool Equals<T>(this T? left, T right) where T : struct, IEquatable<T>
    {
        if (!left.HasValue)
            return false;

        return right.Equals(left.Value);
    }
}

この電話が必要な理由について質問しました。

拡張メソッドに強制しなければならない理由は、適切なメソッドが存在しない場合にのみ拡張メソッドを使用するコンパイラの実装によるものであることが判明しました。この場合、後者が拡張メソッドであるEquals(object)よりも適切であると見なされます。Equals<T>(T)それは仕様にあります。

于 2013-09-11T07:55:20.077 に答える