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