Почему этот, казалось бы, правильный код .NET компилируется?
Я прошу на случай, если я пропущу что-то очевидное, но я думаю, что, возможно, наткнулся на ошибку в компиляторе .NET.
У меня есть два проекта в .NET-решении, один визуальный базовый, один С#.
Код С#, состоящий из трех перегруженных статических методов со значениями по умолчанию:
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)
{
}
}
Визуальный базовый код, вызывающий один из перегруженных методов:
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, вы получите
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 более ограничен, чем С#, при перегрузке необязательных параметров.
Ответ 2
В конечном итоге, похоже, сводится к тому, как С# реализует необязательные параметры в вашем первом статическом методе. Если вы удалите значение по умолчанию, ваше решение должно скомпилироваться.
public static void TestFunc(int val1, int val2)
{
}
Собственно, в этом случае я несколько удивлен, что компиляция С#. Вы должны использовать необязательные параметры в С# или перегрузках, но не оба. Например, как бы вы устранили проблему:
public static void TestFunc(int val1, int val2 = 0)
{
}
public static void TestFunc(int val1)
{
}
Если я передам следующее, какой из двух методов должен быть выполнен - тот, у которого есть необязательный параметр, или второй без второго параметра?
TestFunc(1)
Лучшим решением, если вы хотите включить дополнительные параметры в реализацию С#, было бы объединение первого и второго методов и, при необходимости, проверка значения по умолчанию:
public static void TestFunc(int val1, int val2 = 0)
{
}
public static void TestFunc(string val1, int val2 = 0)
{
}
Примечание. Используя эту версию, VB IS может устранить, какой метод вызывать.
Ответ 3
Изменить
Когда этот вопрос был сначала опубликован как:
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 может преобразовать целое число в строку.
Ответ 4
TestFunc неоднозначен из-за параметра по умолчанию. Когда вызывается TestFunc (x), он не уверен, вызывает ли он вызов TestFunc с одним параметром или TestFunc с параметрами по умолчанию 2. Второй параметр по умолчанию один.
Ответ 5
В 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
неоднозначна.
Я не могу найти что-либо в спецификации С#, которая гласит, что дополнительные параметры рассматриваются как методы с несколькими сигнатурами. Из поведения, которое вы видите, я предполагаю, что в С# у них не считается несколько подписей, иначе вы получите ошибку компилятора, а это значит, что она действительна на С#. Я предполагаю, что С# выберет метод, который вызывается на основе некоторых правил, поскольку он не может вызвать оба для TestFunc(0)
.