Почему это, казалось бы, не будет правильным.ЧИСТЫЙ код компилируется?

#c# #.net #vb.net #static-analysis

#c# #.net #vb.net #статический анализ

Вопрос:

Я спрашиваю на случай, если я упускаю что-то очевидное, но мне кажется, я, возможно, наткнулся на ошибку.Компилятор 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’ существует несколько типов членов с таким именем.

Почему он считает этот метод неоднозначным? Существует только один Class1.TestFunc с сигнатурой (int, int). Это ошибка, или я что-то упустил?

Комментарии:

1. Я бы предположил (хотя кто-то, кто знает VB.NET лучше должно подтвердить / опровергнуть), что As Integer недостаточно сильный, чтобы диктовать тип первого аргумента.

2. Кстати, я не думаю, что иметь два таких метода — хорошая идея. Конечно, компилятор, похоже, согласен с этим, но если бы я читал ваш код и видел TestFunc( 10 ) , я бы не сразу понял, какой метод вызывается.

3. Я думаю, что единственное решение — найти барсука, гриб и змею и спонтанно начать петь.

4. @JonH: Да, я так и думал. Еще одна причина не любить VB…

5. @Вся причина, по которой это сейчас такая большая проблема, заключается в том, что редактирование вопроса было сделано для добавления Option Strict On . Без этой ключевой детали код будет выполняться и будет неоднозначным, поскольку вызов TestFunc дублируется, даже если передается целое число — из-за неявного преобразования. Но теперь вопрос меняется, потому что @w.brian добавлен Option Strict On в код.

Ответ №1:

В конечном счете, похоже, все сводится к тому, как 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 может устранить неоднозначность, какой метод вызывать.

Комментарии:

1. 1 это был правильный ответ, просто мне было трудно сформулировать его так хорошо :).

Ответ №2:

Если вы попытаетесь скомпилировать это в 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 #, в перегрузке необязательных параметров.

Комментарии:

1. Это, безусловно, дает ответ на вопрос. Кажется менее идеальным, чтобы что-то, что совершенно законно в C #, не сработало в VB менее очевидным образом, особенно учитывая, что компилятор может с абсолютной уверенностью определить, какая сигнатура метода вызывается.

2. @ChrisDunaway C # может сделать это без проблем. У него есть некоторые правила. Он предпочитает методы без дополнительных аргументов методам с дополнительными аргументами. Читайте здесь msdn.microsoft.com/en-us/library/dd264739.aspx

3. Я не понимаю, как компилятор мог различать первый и второй методы в исходном вопросе для вызовов формы TestFunc(integer_value) .

Ответ №3:

TestFunc неоднозначен из-за параметра по умолчанию. Когда вызывается TestFunc(x), он не уверен, вызывает ли он TestFunc с одним параметром или TestFunc с параметрами по умолчанию 2. 2-й параметр является параметром по умолчанию.

Комментарии:

1. Он не звонит TestFunc(x) ! Он звонит TestFunc(x, 0) .

2. этот вызов в порядке, компилятору не понравились другие его неоднозначные функции.

3. Мне очень жаль, но я думаю, что вы ошибаетесь. Неоднозначность заключается в двух функциях, которые принимают два параметра.

4. @Bipins Это просто не тот случай. Здесь нет никакой двусмысленности. Вызов TestFunc(1) просто вызовет версию с одним параметром.

5. является ли проблемой VB идентифицировать целое число и строку?

Ответ №4:

Редактировать

Когда этот вопрос был впервые опубликован, оба:

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 может преобразовать целое число в строку.

Комментарии:

1. Так ли это? val1 — это string или int — достаточно, чтобы дать ему отдельную подпись.

2. @TomTom его nto такой же, как C #.

3. Это не «почему», это повторение того, что компилятор уже сказал нам.

4. @EdS. Если вы передаете целое число в функцию, ожидающую строку vb.net может преобразовать это значение int в строку.

5. Я думаю, @w.brian имел в виду параметр Strict On — который отключит неявные преобразования.

Ответ №5:

В спецификации языка Visual Basic 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) so TestFunc неоднозначно.

Я не могу найти ничего в спецификации C #, в которой говорится, что необязательные параметры обрабатываются как методы с несколькими сигнатурами. Из поведения, которое вы видите, я предполагаю, что в C # они не считаются имеющими несколько подписей, в противном случае вы получите ошибку компилятора, что означает, что она действительна в C #. Я предполагаю, что C # выберет метод, который вызывается на основе некоторых правил, поскольку он не может вызывать оба for TestFunc(0) .

Комментарии:

1. Дело скорее в том, что метод с одним аргументом не может быть кандидатом для этого вызова в C # — VB сразу отклоняет группу методов (я не уверен, появится ли она вообще в intellisense), а не просто при вызове с набором аргументов, которые могут разрешаться более чем одним. РЕДАКТИРОВАТЬ также кажется, что C # предпочтет метод с меньшим количеством необязательных параметров, но если у вас есть два метода с одинаковым номером, вы все равно можете получить неоднозначную ошибку, но только если вы на самом деле их вызываете.