Тени против перегрузки в VB.NET
Когда у нас есть new
в С#, я лично вижу только в качестве обходного пути для переопределения свойства, у которого нет объявления virtual/overridable, в VB.NET у нас есть две "понятия" Shadows
и Overloads
.
В этом случае предпочитаете друг друга?
Ответы
Ответ 1
Существует три тесно связанных понятия; переопределение, затенение и перегрузка.
Переопределение - это когда вы создаете новую реализацию для виртуального метода.
Тень - это когда вы создаете новую не виртуальную реализацию для метода.
Перегрузка - это когда вы добавляете метод с тем же именем, но с разными параметрами.
Все три понятия доступны как в С#, так и в VB.
Ответ 2
Я действительно подтвердил, компилируя тот же код с Shadows
vs Overloads
для метода с идентичным именем и сигнатурой в базовом классе и глядя на вывод из ildasm
для обоих. Единственное отличие - это случай Overloads
указывает hidebysig
.
Значение этого лучше всего объяснить Jon Skeet в этом ответе.
Но просто это означает, что существует только реальная разница, если базовый класс имеет перегрузки переопределенного метода:
-
Shadows
приведет к тому, что все эти
перегрузки должны быть недопустимыми через
производный класс, где
-
Overloads
заменяет только один метод.
Обратите внимание, что это только языковая конструкция и не выполняется CLI (т.е. С# и VB.NET применяют это, но другие языки не могут).
Пример простого кода:
Module Module1
Sub Main()
Dim a1 As C1 = New C2
Dim a2 As New C2
a1.M1()
a2.M1()
a1.M2()
a2.M2()
a1.M3()
a2.M3()
a1.M1(1)
' Overloads on M1() allows the M1(int) to be inherited/called.
a2.M1(1)
a1.M2(1)
' Shadows on M2() does not allow M2(int) to be called.
'a2.M2(1)
a1.M3(1)
' Shadows on M3() does not allow M3(int) to be called, even though it is Overridable.
'a2.M3(1)
If Debugger.IsAttached Then _
Console.ReadLine()
End Sub
End Module
Class C1
Public Sub M1()
Console.WriteLine("C1.M1")
End Sub
Public Sub M1(ByVal i As Integer)
Console.WriteLine("C1.M1(int)")
End Sub
Public Sub M2()
Console.WriteLine("C1.M2")
End Sub
Public Sub M2(ByVal i As Integer)
Console.WriteLine("C1.M2(int)")
End Sub
Public Overridable Sub M3()
Console.WriteLine("C1.M3")
End Sub
Public Overridable Sub M3(ByVal i As Integer)
Console.WriteLine("C1.M3(int)")
End Sub
End Class
Class C2
Inherits C1
Public Overloads Sub M1()
Console.WriteLine("C2.M1")
End Sub
Public Shadows Sub M2()
Console.WriteLine("C2.M2")
End Sub
Public Shadows Sub M3()
Console.WriteLine("C2.M3")
End Sub
' At compile time the different errors below show the variation.
' (Note these errors are the same irrespective of the ordering of the C2 methods.)
' Error: 'Public Overrides Sub M1(i As Integer)' cannot override 'Public Sub M1(i As Integer)' because it is not declared 'Overridable'.
'Public Overrides Sub M1(ByVal i As Integer)
' Console.WriteLine("C2.M1(int)")
'End Sub
' Errors: sub 'M3' cannot be declared 'Overrides' because it does not override a sub in a base class.
' sub 'M3' must be declared 'Shadows' because another member with this name is declared 'Shadows'.
'Public Overrides Sub M3(ByVal i As Integer)
' Console.WriteLine("C2.M3(int)")
'End Sub
End Class
Результат выше:
C1.M1
C2.M1
C1.M2
C2.M2
C1.M3
C2.M3
C1.M1(int)
C1.M1(int)
C1.M2(int)
C1.M3(int)
Вывод показывает, что вызовы Shadows
используются, когда C2
вызывается напрямую, а не при вызове косвенно через C1
.
Ответ 3
Shadows
предназначен для случаев, когда ваш базовый класс Function SomeMethod() As String
, и вы хотите иметь Function SomeMethod() As Integer
. В принципе, для изменения типа возврата.
Overloads
предназначен для случая, когда ваш базовый класс Function SomeMethod() As String
, и вы хотите добавить такой параметр, как Function SomeMethod(ByVal value As Integer) As String
.
Ответ 4
В документации Microsoft указано:
Затенение и перегрузка. Overloads
также может использоваться для теневого копирования существующего члена или набора перегруженных членов в базовом классе. Когда вы используете Overloads
таким образом, вы объявляете свойство или метод с тем же именем и тем же списком параметров, что и член базового класса, и не предоставляете ключевое слово Shadows
.
Следовательно, результат тот же: дочерний элемент заменяет базовый элемент. Однако причины, по которым вы можете достичь такого результата, обычно подразделяются на две категории:
- Тени - Вы хотите убедиться, что член вашего дочернего класса не будет затронут в случае, если новый член с тем же именем будет впоследствии добавлен в базовый класс. В этом случае затененный элемент обычно еще не существует; вы только хотите предвидеть проблемы на будущее.
- Перегрузки. Вы хотите заменить реализацию члена базового класса на класс вашего дочернего класса. В этом случае перегруженный элемент уже существует; вы хотите изменить поведение.
Теперь, имея в виду, что затененный элемент обычно не существует во время определения затененного элемента, причины, по которым компилятор по умолчанию предполагает Shadows
, становятся очевидными.
Части, относящиеся к ключевому слову Shadows
этой статьи Microsoft, также заслуживают прочтения.