C# Nullable上的扩展方法<;T>;除非显式设置了泛型类型,否则不调用

C# Nullable上的扩展方法<;T>;除非显式设置了泛型类型,否则不调用,c#,extension-methods,C#,Extension Methods,在研究另一个问题时:“我在null可上做了一个扩展方法,它公开了一个通用的Equals(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;

在研究另一个问题时:“我在
null可
上做了一个扩展方法,它公开了一个通用的
Equals(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);
    }
}
通过装箱调用base
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)
IL_0000:nop
IL_0001:ldloca.s d
IL_0003:initobj valuetype[mscorlib]系统。可为null`1
IL_0009:ldloca.s d
IL_000b:ldc.r8 0.0
IL_0014:box[mscorlib]System.Double
IL_0019:受约束。valuetype[mscorlib]系统。可为null`1
IL_001f:callvirt实例bool[mscorlib]System.Object::Equals(Object)
如果我将调用更改为显式声明泛型类型:

d.Equals<double>(0.0);
d.Equals(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)
IL_0000:nop
IL_0001:ldloca.s d
IL_0003:initobj valuetype[mscorlib]系统。可为null`1
IL_0009:ldloc.0
IL_000a:ldc.r8 0.0
IL_0013:调用bool控制台应用程序8.NullableExtensions::Equals(valuetype[mscorlib]System.Nullable`1,!!0)
为什么编译器不选择扩展方法而不是
Equals(object)
方法

是不是因为我刚刚选择了一个糟糕的方法名
Equals(T)
,它实际上不是
Equals
的真正重写,也不是继承查找的一部分

为什么编译器不选择扩展方法而不是Equals(object)方法

只有在没有其他替代方案的情况下才考虑扩展方法。这是一种退步——对于实例方法来说,它不是正常重载解析的一部分。这并不特定于可为null的类型,而是普通扩展方法调用的一部分

根据规范第7.6.5.2节:

在其中一个窗体的方法调用中

[……]

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


(重点是我的。)

啊,我怀疑这方面有什么问题,因此需要事先明确说明。我不确定是高兴还是悲伤,因为我花了更长的时间来提出这个问题,而不是得到答案:——)
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)