23

当我们new在 C# 中时,我个人认为这只是一种解决方法来覆盖没有虚拟/可覆盖声明的属性,在 VB.NET 中我们有两个“概念”ShadowsOverloads.

在哪种情况下更喜欢一个?

4

4 回答 4

22

实际上,我已经通过使用ShadowsvsOverloads为基类中具有相同名称和签名的方法编译相同的代码并查看ildasm两者的输出来确认。唯一的区别是Overloads大小写指定hidebysig

Jon Skeet 在这个答案中最好地解释了这一点的重要性。

但简单地说,这意味着只有基类具有被重新定义的方法的重载时才会有真正的区别:

  • 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

于 2011-01-21T15:37:28.820 回答
16

存在三个密切相关的概念;覆盖,阴影和重载。

覆盖是当您为虚拟方法创建新实现时。

阴影是当您为方法创建新的非虚拟实现时。

重载是当您添加具有相同名称但不同参数的方法时。

这三个概念在 C# 和 VB 中都可用。

于 2010-03-25T11:43:03.550 回答
1

Microsoft 文档指出:

阴影和重载Overloads也可用于隐藏基类中的现有成员或重载成员集。以这种方式使用Overloads时,您声明的属性或方法与基类成员具有相同的名称和相同的参数列表,并且您不提供Shadows关键字。

因此,结果是相同的:子成员替换了基础成员。但是,您可能希望获得此类结果的原因通常分为两类:

  • 阴影- 您希望确保您的子类的成员不会受到影响,以防随后将具有相同名称的新成员添加到基类中。在这种情况下,阴影成员通常还不存在;你只希望预测未来的问题
  • 重载- 您希望用您的子类替换基类中成员的实现。在这种情况下,重载的成员已经存在;你想改变一个行为

现在考虑到在定义遮蔽成员时通常不存在遮蔽成员,编译器默认假设的原因Shadows变得显而易见。

提到这篇微软文章Shadows的关键字的部分也值得一读。

于 2019-09-17T15:05:16.060 回答
0

Shadows适用于您的基类是Function SomeMethod() As String并且您希望拥有Function SomeMethod() As Integer. 基本上,改变返回类型。

Overloads适用于您的基类是Function SomeMethod() As String并且您想要添加参数的情况,例如Function SomeMethod(ByVal value As Integer) As String.

于 2010-03-25T11:40:38.673 回答