6

Why は次のようにThrowIfNull実装されています。

    static void ThrowIfNull<T>(this T argument, string name) where T : class
    {
        if (argument == null)
        {
            throw new ArgumentNullException(name);
        }
    }

次のように書き直したほうがよいのではないでしょうか。

    static void ThrowIfNull<T>(this T argument, string name) where T : class
    {
        if (object.ReferenceEquals(argument, null))
        {
            throw new ArgumentNullException(name);
        }
    }

長所: 混乱を招くオーバーロードを回避するのに役立ちEquals、おそらくコードがより明確になります。

それに対する短所はありますか?いくつかあるはずです。

4

3 に答える 3

12

両者に違いはありません。オーバーライド Equals(どちらの実装でも呼び出されない)とオーバーロード ==(オーバーロードはコンパイル時に実行され、コンパイラはT特定のオーバーロードの使用について十分に認識していないため、どちらのスニペットでも関係ありません)を混同しています。 .

私が何を意味するかを示すために:

static void ThrowIfFoo<T>(this T argument, string name) where T : class
{
    if (argument == "foo")
    {
        throw new Exception("You passed in foo!");
    }
}

テスト:

"foo".ThrowIfFoo(); // Throws

string x = "f";
x += "oo"; // Ensure it's actually a different reference

x.ThrowIfFoo(); // Doesn't throw

ThrowIfFooそれが文字列になるかどうかはわかりません- それは呼び出し元Tのコードに依存するためです - そしてオーバーロードの解決はがコンパイルされたときにのみ実行されます。したがって、ではなく演算子を使用しています。ThrowIfFoo==(object, object)==(string, string)

つまり、次のようになります。

object foo1 = "foo";

string tmp = "f";
object foo2 = tmp + "oo";

Console.WriteLine(foo1.Equals(foo2)); // Prints True
Console.WriteLine(foo1 == foo2); // Prints false
Console.WriteLine((string) foo1 == (string) foo2); // Prints True

最後の行で、コンパイラは == のオーバーロードを使用できることを認識しています。これは、両方のオペランドのコンパイル時の型が であるためstringです。

于 2011-08-19T09:34:11.967 に答える
5

==演算子は実行時ではなくコンパイル時に解決されます。一般T的であるため、コンパイラーは、参照の同等性をチェックする、それ自体が==提供するの実装を使用します。object

これもまさにその通りです。によって提供される実装をobject.ReferenceEquals呼び出します。==object

于 2011-08-19T09:32:56.927 に答える
1

これは主に化粧品です。

obj == nullは参照チェックを実行して戻ります。Equals引数がnullで、でオーバーライドされていない場合も同様Tです。1つの引数がnullの場合にtrueを返すには、かなり不安定で悪意のある実装が必要になります。

于 2011-08-19T09:32:04.320 に答える