3

別の質問を調査しているときに、「 Nullable<T>.Equals(T value) メソッドがないのはなぜですか?Nullable<T> 」ジェネリックメソッドを公開する拡張メソッドを作成しましたEquals<T>(T):

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);
    }
}

ただし、次のように呼び出します。

double? d = null;
d.Equals(0.0);

Equals(object)IL でわかるように、ボクシングでベースにコールします。

IL_0000: nop
IL_0001: ldloca.s d
IL_0003: initobj valuetype [mscorlib]System.Nullable`1<float64>
IL_0009: ldloca.s d
IL_000b: ldc.r8 0.0
IL_0014: box [mscorlib]System.Double
IL_0019: constrained. valuetype [mscorlib]System.Nullable`1<float64>
IL_001f: callvirt instance bool [mscorlib]System.Object::Equals(object)

ジェネリック型を明示的に記述するように呼び出しを変更すると、次のようになります。

d.Equals<double>(0.0);

それは私の拡張メソッドを呼び出します:

IL_0000: nop
IL_0001: ldloca.s d
IL_0003: initobj valuetype [mscorlib]System.Nullable`1<float64>
IL_0009: ldloc.0
IL_000a: ldc.r8 0.0
IL_0013: call bool ConsoleApplication8.NullableExtensions::Equals<float64>(valuetype [mscorlib]System.Nullable`1<!!0>, !!0)

コンパイラがメソッドではなく拡張メソッドを選択しないのはなぜEquals(object)ですか?

Equals<T>(T)それは、実際には真のオーバーライドではEqualsなく、継承ルックアップの一部ではない、貧弱なメソッド名を選択したからですか?

4

1 に答える 1

9

コンパイラが Equals(object) メソッドよりも拡張メソッドを選択しないのはなぜですか?

拡張メソッドは、他に選択肢がない場合にのみ考慮されます。これはフォールバックです。インスタンス メソッドの通常のオーバーロード解決の一部ではありません。これは、null 許容型に固有のものではなく、通常の拡張メソッド呼び出しの一部です。

仕様のセクション 7.6.5.2 から:

いずれかのフォームのメソッド呼び出しで

[...]

呼び出しの通常の処理で適用可能なメソッドが見つからない場合、構成を拡張メソッド呼び出しとして処理しようとします。

(私のものを強調してください。)

于 2013-09-11T08:26:07.070 に答える