【问题标题】:Shadows vs Overloads in VB.NETVB.NET 中的阴影与重载
【发布时间】:2011-01-31 16:24:57
【问题描述】:

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

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

【问题讨论】:

    标签: .net vb.net oop overloading shadows


    【解决方案1】:

    我实际上已经通过使用ShadowsOverloads 编译相同的代码来确认基类中具有相同名称和签名的方法,并查看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 间接调用时使用。

    【讨论】:

    • 这绝对应该是公认的答案,因为它解释了这两个概念之间的关键区别,我们可以从逻辑上推断出其他答案中描述的所有其他差异。
    【解决方案2】:

    有三个密切相关的概念;覆盖、遮蔽和重载。

    覆盖是指为虚拟方法创建新实现。

    Shadowing 是指为方法创建新的非虚拟实现。

    重载是指添加同名但参数不同的方法。

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

    【讨论】:

    • 问题不在于覆盖,这没关系。现在,Overloads 也可用于隐藏 基类中的现有成员或重载成员集。当您以这种方式使用重载时,您声明的属性或方法与基类成员具有相同的名称和相同的参数列表,并且您不提供 Shadows 关键字。我看到 new (C#) = Shadows (VB.NET),什么是 C# 等价于重载?
    • @serhio:我刚刚提到为了完整性而重写,因为它是一个密切相关的概念。由于 VB 中的 Overloads 关键字也可用于阴影,因此在 C# 中没有完全等价的。 C#中没有重载的关键字,你只需声明一个同名不同签名的方法来重载它。
    • 所以,你的定义不完整,所以这两个概念对我来说仍然不清楚。 Shadows 创建一个“新”函数,Overloads (可以)用于相同的范围。那么有什么区别呢。
    • @serhio:嗯,这些概念的定义已经很完整了(当然还有很多关于它们的解释)。这些概念不会一对一地映射到 VB 关键字,因此虽然您有时可以使用 Overloads 关键字来遮蔽它,但您所做的仍然是遮蔽。即使 VB 关键字重叠,概念也保持不变。
    • 我同意。但是在实践中我使用关键字而不是概念,如果我在子类中使用相同的(非虚拟)方法和相同的参数,VS 会警告我使用“Overloads”关键字,而不是“Shadows”关键字,例如它应该来自您描述的概念。
    【解决方案3】:

    Microsoft documentation 表示:

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

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

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

    现在考虑到在定义影子成员时通常不存在影子成员,编译器默认假定Shadows 的原因就很明显了。

    这个Microsoft articleShadows关键字的部分也值得一读。

    【讨论】:

      【解决方案4】:

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

      Overloads 适用于您的基类为 Function SomeMethod() As String 并且您想要添加诸如 Function SomeMethod(ByVal value As Integer) As String 之类的参数的情况。

      【讨论】:

      • 重载也可用于阴影基类中的现有成员或重载成员集。以这种方式使用重载时,您声明的属性或方法与基类成员具有相同的名称和相同的参数列表,并且您不提供 Shadows 关键字。
      猜你喜欢
      • 2013-06-13
      • 2016-01-04
      • 1970-01-01
      • 2016-11-06
      • 1970-01-01
      • 1970-01-01
      • 2015-08-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多