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) 方法的扩展方法?

只有在没有其他替代方案时才考虑扩展方法。这是一个后备 - 它不是实例方法的正常重载解决方案的一部分。这并不特定于可空类型 - 它是正常扩展方法调用的一部分。

从规范的第 7.6.5.2 节:

在其中一种形式的方法调用中

[...]

如果调用的正常处理没有找到适用的方法,则尝试将构造作为扩展方法调用进行处理。

(强调我的。)

于 2013-09-11T08:26:07.070 回答