VB.NET编译器如何选择运行哪个扩展重载?

Jam*_*ose 7 .net vb.net extension-methods overloading

有一个有趣的奇怪 - 认为有人可能会帮助.

这可以从这个问题的可空类型中获得一些乐趣:

如何检查对象是否可以为空?

Option Strict On

Module Test
  ' Call this overload 1
  <Extension()>
  Function IsNullable(obj As ValueType) As Boolean
    Return False
  End Function

  ' Call this overload 2
  <Extension()>
  Function IsNullable(Of T As {Structure})(obj As Nullable(Of T)) As Boolean
    Return True
  End Function

  Sub Test() 
    ' a is an integer!
    Dim a As Integer = 123

    ' calling IsNullable as an extension method calls overload 1 and returns false
    Dim result1 As Boolean = a.IsNullable()

    ' calling IsNullable as method calls overload 2 and returns true
    Dim result2 As Boolean = IsNullable(a)

    ' why? surely the compiler should treat both those calls as equivalent
  End Sub
End Module
Run Code Online (Sandbox Code Playgroud)

我希望编译器对IsNullable的两次调用都是一样的,但事实并非如此.即使参数"a"未更改,扩展方法调用也会对普通方法调用使用不同的重载.

我的问题是为什么?是什么让编译器在两次调用之间改变主意?

FTR:我们使用的是Visual Studio 2010,.NET Framework 4.

Mar*_*urd 0

认为这是一个错误,或者至少是 VB.NET“功能”。(我只是不确定 VB.NET 或 C# 哪个是错误的。)

我已经在 LINQPad 4 中进行了尝试(因为这就是我正在使用的机器上得到的),对于 C#,我得到了两个结果,当然,False除了类型之外的每个值类型和枚举。Nullable

而对于 VB.NET,我得到了所有值类型和枚举的Falseand True,除了Nullable类型, and ValueType[Enum]它返回FalseFalse因为你不能有ValueType?or [Enum]?。使用Option Strict Off,Object会导致后期绑定,并且在运行时无法找到任一重载,但第二个结果也是False因为您无法拥有Object?.

为了完整起见,按预期为两种语言Nullable键入 return True, 。True

事实上,C# 正在做一些不同的事情(假设我的测试是正确的),这证实了对 C#“更好转换”检查的引用是错误的(或者至少被误读了 - 因为 C# 没有做被解释为 VB.NET 的原因)正在做它正在做的事情)。

但是,我确实同意该问题可能与隐式转换为Nullable(Of T)现有的并且以某种方式比隐式转换为更高的优先级有关ValueType

这是我的 LINQPad 4“查询”(C# 程序):

void Main()
{
    Test.test();
}

// Define other methods and classes here
static class Test
{
    static bool IsNullable(this ValueType obj)
    {
        return false;
    }

    static bool IsNullable<T>(this T? obj) where T:struct
    {
        return true;
    }

    public static void test()
    {
        int x = 42;

        bool result1 = x.IsNullable();
        bool result2 = IsNullable(x);

        result1.Dump("result1");
        result2.Dump("result2");
    }
}
Run Code Online (Sandbox Code Playgroud)