Тени против перегрузок в VB.NET

Когда у нас new в C# это лично я вижу только в качестве обходного пути для переопределения свойства, которое не имеет виртуального / переопределяемого объявления, в VB.NET у нас есть две "концепции" Shadows а также Overloads,

В каком случае предпочитаете одно другому?

3 ответа

Решение

Есть три тесно связанных понятия; переопределение, затенение и перегрузка.

Переопределение - это когда вы создаете новую реализацию для виртуального метода.

Затенение - это когда вы создаете новую не виртуальную реализацию для метода.

Перегрузка - это когда вы добавляете метод с тем же именем, но с другими параметрами.

Все три концепции доступны как в C#, так и в VB.

Я фактически подтвердил, компилируя тот же код с Shadows против Overloads для метода с идентичным именем и сигнатурой в базовом классе и глядя на вывод из ildasm для обоих. Единственная разница заключается в Overloads дело указывает hidebysig,

Значение этого лучше всего объяснить Джоном Скитом в этом ответе.

Но просто это означает, что есть реальная разница, только если базовый класс перегружен переопределяемым методом:

  • Shadows вызовет невозможность вызова всех этих перегрузок через производный класс, где
  • Overloads заменяет только один метод.

Обратите внимание, что это только языковая конструкция и не применяется CLI (то есть C# и 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,

В документации Microsoft указано:

Затенение и перегрузка.Overloadsтакже может использоваться для теневого копирования существующего члена или набора перегруженных членов в базовом классе. Когда вы используетеOverloads таким образом вы объявляете свойство или метод с тем же именем и тем же списком параметров, что и член базового класса, и не предоставляете Shadows ключевое слово.

Следовательно, результат тот же: дочерний элемент заменяет базовый член. Однако причины, по которым вы можете захотеть достичь такого результата, обычно делятся на две категории:

  • Тени - вы хотите убедиться, что член вашего дочернего класса не будет затронут в случае, если новый член с тем же именем впоследствии будет добавлен к базовому классу. В этом случае теневой элемент обычно еще не существует; вы хотите только предвидеть проблемы в будущем.
  • Перегрузки - вы хотите заменить реализацию члена в базовом классе этим одним из вашего дочернего класса. В этом случае перегруженный элемент уже существует; вы хотите изменить поведение.

Имея в виду, что теневой член обычно не существует во время определения теневого члена, причины, по которым по умолчанию компилятор будет принимать Shadows стать очевидным.

Части, относящиеся к Shadowsключевое слово этой статьи Microsoft также стоит прочитать.

Shadows для случаев, когда ваш базовый класс Function SomeMethod() As String и ты хочешь иметь Function SomeMethod() As Integer, В основном, чтобы изменить тип возвращаемого значения.

Overloads для случая, когда ваш базовый класс Function SomeMethod() As String и вы хотите добавить параметр, такой как Function SomeMethod(ByVal value As Integer) As String,

Другие вопросы по тегам