为什么这个看似正确的.NET代码不能编译?

时间:2011-10-25 18:06:40

标签: c# .net vb.net static-analysis

我问的是,如果我遗漏了一些明显的东西,但我想我可能偶然发现了.NET编译器中的一个错误。

我在.NET解决方案中有两个项目,一个是Visual Basic,一个是C#。

C#代码,由三个带有默认值的重载静态方法组成:

public static class Class1
{

    public static void TestFunc(int val1, int val2 = 0)
    {
    }

    public static void TestFunc(int val1 = 0)
    {
    }

    public static void TestFunc(string val1, int val2 = 0)
    { 
    }
}

Visual Basic代码,调用其中一个重载方法:

Option Explicit On
Option Strict On
Imports ClassLibrary1

Module Module1
    Sub Main()
        Dim x As Integer
        Class1.TestFunc(x, 0)
    End Sub
End Module

编译此代码将失败,说:

'TestFunc'不明确,因为类'ClassLibrary1.Class1'中存在多种具有此名称的成员。

为什么它会将此方法视为含糊不清?只有一个带有(int,int)签名的Class1.TestFunc。这是一个错误,还是我错过了什么?

5 个答案:

答案 0 :(得分:23)

最终,它似乎归结为C#如何在第一个静态方法中实现可选参数。如果删除默认值,则应该编译解决方案。

public static void TestFunc(int val1, int val2) 
{ 
} 

实际上,在这种情况下,我对C#编译感到有些惊讶。您应该在C#中使用可选参数或重载,但不能同时使用两者。例如,您将如何消除以下歧义:

public static void TestFunc(int val1, int val2 = 0)     
{     
}     

public static void TestFunc(int val1)     
{     
}  

如果我传入以下内容,应该执行两种方法中的哪一种 - 带有可选参数的方法或带有第二个参数的第二种方法?

TestFunc(1)

如果要在C#实现中包含可选参数,更好的解决方案是组合第一种和第二种方法并根据需要检查默认值:

public static void TestFunc(int val1, int val2 = 0)
{
}

public static void TestFunc(string val1, int val2 = 0)
{
}

注意,使用此版本,VB IS能够消除要调用的方法的歧义。

答案 1 :(得分:15)

如果您尝试在VB.NET中编译它,您将获得

Sub TestFunc(ByVal val1 As Integer, Optional ByVal val2 As Integer = 0)

End Sub

Sub TestFunc(Optional ByVal val1 As Integer = 0)

End Sub

你会得到Public Sub TestFunc(val1 As Integer, [val2 As Integer = 0])' and 'Public Sub TestFunc([val1 As Integer = 0])' cannot overload each other because they differ only by optional parameters.

所以我会说VB.NET在可选参数重载方面比C#更受限制。

答案 2 :(得分:2)

修改

当这个问题首次发布时:

Option Strict On

Option Explicit On

没有提出问题所以这会彻底改变答案。

问题编辑前的原始答案

因为:

 public static void TestFunc(int val1, int val2 = 0) 
    { 
    } 

不明确:

public static void TestFunc(string val1, int val2 = 0) 
    {  
    } 

VB.net可以将整数转换为字符串。

答案 3 :(得分:2)

由于默认参数,TestFunc不明确。当调用TestFunc(x)时,它不确定它是使用单个参数调用TestFunc还是使用默认2参数调用TestFunc第二个参数是默认值。

答案 4 :(得分:2)

Visual Basic Language Specification 10中说明了这一点。

  

具有可选参数的方法被认为具有多个   签名,每个参数可以传入一个   呼叫者,召集者。例如,以下方法有三个对应的   签名:

 Sub F(x As Short, _
       Optional y As Integer = 10, _
       Optional z As Long = 20)

因此,您的TestFunc(int val1, int val2 = 0)在VB中有两个签名,与TestFunc(int val1)冲突,因此TestFunc不明确。

我在C#规范中找不到任何说明可选参数被视为具有多个签名的方法的内容。从你看到的行为我假设在C#中它们不被认为有多个签名,否则你会得到编译器错误 - 这意味着它在C#中是有效的。我假设C#将根据某些规则选择被调用的方法,因为它不能同时调用TestFunc(0)