Nullable <t>上的扩展方法未被调用,除非明确设置泛型类型</t>

时间:2013-09-11 08:24:32

标签: c# extension-methods

在调查另一个问题时:“Why there is no Nullable<T>.Equals(T value) method?”我在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的真正覆盖而不是继承查找的一部分?

1 个答案:

答案 0 :(得分:9)

  

为什么编译器没有选择Equals(object)方法的扩展方法?

如果没有其他替代方案,则仅考虑扩展方法 。这是一个后备 - 它不是实例方法的正常重载分辨率的一部分。这不是特定于可空类型 - 它是正常扩展方法调用的一部分。

来自规范的第7.6.5.2节:

  

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

     

[...]

     

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

(强调我的。)