【发布时间】:2011-01-31 16:24:57
【问题描述】:
当我们在 C# 中有 new 时,我个人认为这只是一种解决方法来覆盖没有虚拟/可覆盖声明的属性,在 VB.NET 中我们有两个“概念”Shadows 和 @987654323 @。
在哪种情况下更喜欢另一种?
【问题讨论】:
标签: .net vb.net oop overloading shadows
当我们在 C# 中有 new 时,我个人认为这只是一种解决方法来覆盖没有虚拟/可覆盖声明的属性,在 VB.NET 中我们有两个“概念”Shadows 和 @987654323 @。
在哪种情况下更喜欢另一种?
【问题讨论】:
标签: .net vb.net oop overloading shadows
我实际上已经通过使用Shadows 与Overloads 编译相同的代码来确认基类中具有相同名称和签名的方法,并查看ildasm 的输出。唯一的区别是Overloads case 指定hidebysig。
Jon Skeet 在this answer 中最好地解释了这一点的重要性。
但这只是意味着如果基类具有被重新定义的方法的重载,则只有真正的区别:
Shadows 将导致所有
重载无法通过
派生类,其中为 Overloads 只替换了 one 方法。请注意,这只是一种语言结构,并非由 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 间接调用时使用。
【讨论】:
有三个密切相关的概念;覆盖、遮蔽和重载。
覆盖是指为虚拟方法创建新实现。
Shadowing 是指为方法创建新的非虚拟实现。
重载是指添加同名但参数不同的方法。
这三个概念在 C# 和 VB 中都可用。
【讨论】:
Shadows 创建一个“新”函数,Overloads (可以)用于相同的范围。那么有什么区别呢。
Overloads 关键字来遮蔽它,但您所做的仍然是遮蔽。即使 VB 关键字重叠,概念也保持不变。
阴影和重载。
Overloads也可用于隐藏基类中的现有成员或重载成员集。当你以这种方式使用Overloads时,你声明的属性或方法与基类成员具有相同的名称和相同的参数列表,并且你不提供Shadows关键字。
因此,结果是相同的:子成员替换了基础成员。但是,您可能希望获得这样的结果的原因通常分为两类:
现在考虑到在定义影子成员时通常不存在影子成员,编译器默认假定Shadows 的原因就很明显了。
这个Microsoft article的Shadows关键字的部分也值得一读。
【讨论】:
Shadows 适用于您的基类为Function SomeMethod() As String 并且您希望拥有Function SomeMethod() As Integer 的情况。基本上就是改变返回类型。
Overloads 适用于您的基类为 Function SomeMethod() As String 并且您想要添加诸如 Function SomeMethod(ByVal value As Integer) As String 之类的参数的情况。
【讨论】: