C#vs VB.Net,阴影和[重载(不改变参数)]之间的区别是什么

时间:2016-01-13 14:15:12

标签: c# vb.net oop overloading shadowing

很抱歉这个问题很长,但我对C#不熟悉(我曾经使用过VB.Net)

我完全理解VB.Net和C#中覆盖重载之间的区别。所以覆盖没有问题。

现在,在 VB.Net 中,阴影(使用关键字阴影)和重载(使用关键字Overloads'与相同的论点')如下:

  • 当使用阴影时,它会使用相同的名称隐藏每个方法 - 无论参数如何 - 只变为一个方法(阴影方法)。
  • 当使用重载时 - 使用相同的参数 - 它只会重载(阴影)具有相同名称​​和参数的方法。

考虑以下代码:

Class A
    Sub MyMethod()
        Console.WriteLine("A.MyMethod")
    End Sub
    Sub MyMethod(ByVal x As Integer)
        Console.WriteLine("A.MyMethod (x)")
    End Sub
    Sub MyMethod2()
        Console.WriteLine("A.MyMethod2")
    End Sub
    Sub MyMethod2(ByVal x As Integer)
        Console.WriteLine("A.MyMethod2 (x)")
    End Sub
End Class

Class B
    Inherits A
    Overloads Sub MyMethod()
        Console.WriteLine("B.MyMethod")
    End Sub
    Shadows Sub MyMethod2()
        Console.WriteLine("B.MyMethod2")
    End Sub
End Class

然后:

Dim obj As New B()
obj.MyMethod()      'B.MyMethod
obj.MyMethod(10)    'A.MyMethod (x)
obj.MyMethod2()     'B.MyMethod2

虽然:

obj.MyMethod2(10)   'Error, cuz there's only one 'MyMethod2' (and with zero arguments)

到目前为止一直很好......

但是,在C#中我没有得到阴影(使用关键字New)和重载(相同名称和参数)之间的相同差异!

因此,当在C#中尝试上述相同的代码时(当然使用C#语法:D),以下行:

obj.MyMethod2(10);

将返回>> 'A.MyMethod2(x)'

看起来C#!!中的重载和阴影没什么区别。

任何人都可以解释为什么存在这种差异?

谢谢

5 个答案:

答案 0 :(得分:9)

这是一个令人困惑的问题。让我把它分解成更小的问题。

  

什么是继承

当一个类型从另一个类型继承时,基类型的可继承成员也是派生类型的成员。大多数成员都是可继承的;一些人,比如建设者,不是。

  

所有会员?即使是私人的?

是。私人成员是继承的。

表示,通过名称查找它们可能不合法,但它们仍然是继承的。

  

在C#中,什么是重载方法?

当一种方法有两个相同名称但签名不同的方法时,方法重载。 (出于本讨论的目的,方法的签名包括其名称,通用arity,参数数量和参数类型。)

如果我们有一个类型D有两个成员,M(X)和M(Y),它们是重载的,它们中的一个从基类型B继承,而另一个在D.他们仍然超载。

  

在C#中,如何解决重载?

这个过程很复杂,但基本规则是:首先汇集给定名称的所有可访问方法的集合。然后删除签名与给定参数不匹配的所有方法。其余方法是适用的方法

然后识别并保留最多派生类型中声明的方法;其他适用的方法将被删除。 (重写的方法被认为是最初声明方法的类型的方法,而不是覆盖它们的类型。)

如果剩下一种方法,它就会获胜。否则,评估每对适用的方法,以查看在匹配参数时是否一个比另一个更好;任何比另一种更糟糕的方法都被淘汰了。如果这个过程产生一种独特的最佳方法,那么它就会赢。

还有许多涉及通用方法和破坏者的规则与本讨论无关。

  

在C#中,方法的名称隐藏了什么?

如果在派生类继承的基类中有方法M(X),派生类可以声明同一签名的另一个成员。该成员隐藏基类中的成员。

特别是,如果隐藏方法是一种适用的方法,那么重载决策将选择隐藏任何基类型成员的方法,因为正如我们已经知道的那样,重载决策会丢弃不在其中的成员。 大多数派生类型。由于隐藏方法始终采用比隐藏方法更加派生的类型,因此它总是胜出 - 只要它当然可以访问。

  

在C#中,我们如何将成员标记为隐藏名称?

你不需要做任何事情;只需声明该成员隐藏基类成员。但是,C#编译器会警告您隐藏可能是无意的;它经常是。您可以使用隐藏成员上的new关键字来消除警告。当您打算隐藏成员时,这是最佳做法。

  

在C#中,如果重载解析无法选择隐藏方法,因为它不适用或无法访问,会发生什么?

然后适用通常的重载决策规则。隐藏方法不适用,因此立即从所考虑的方法集中删除。这可能意味着派生类型中声明的方法不适用,因此基类的成员可能是在最派生类型中声明的适用方法。

  

成员阴影如何在VB中工作的规则与C#中的隐藏规则略有不同吗?

  

为什么?

C#和VB虽然故意相似,但在同一个演员身上并不是不同的服装。他们是具有不同历史,不同设计考虑因素和不同设计团队的不同语言。你应该期待像这样的小差异。

  

那么在C#中隐藏方法和重载方法有什么区别?

两者均宣布新成员。添加新重载会添加具有不同签名的方法,并且这些方法可能会也可能不会以相同的类型声明。隐藏方法会添加一个与基本类型中方法的签名完全匹配的新方法。

答案 1 :(得分:3)

C#和VB可能使用相同的框架和IL,但它们不是同一种语言或平台。 VB中不存在C#中的某些功能,而C#中不存在VB中的某些功能。

在这种情况下,在C#中的方法上使用{{1}}关键字不会影响"阴影"。它用于method hiding

答案 2 :(得分:2)

检查this

在C#中,阴影表示您可以完全替换该项目。例如,您可以在父类中隐藏一个名为ToBeShadowed字段,并在其中成为方法 ToBeShadowed()儿童班。在此过程中,每当您使用父类时,该项将是字段,但如果您使用子类,则该项将为方法。因此,阴影允许您完全更改具有相同名称的项目的性质。

public class A {
    public int ToBeShadowed; //This is a field in the parent class
}

public class B : A {
    public void ToBeShadowed(){ //this is a method in the child
        //do something
    }
}
然而, 重载与阴影完全不同。例如,您 重载字段到某个方法。每次重载都必须具有相同的返回值,尽管它可能具有不同的输入参数。因此,重载就像为输入参数提供更多可能性而不改变项的性质。但阴影可以这样做。

public class A { //This is overloading
    public int ToBeOverloaded(); //with no input
    public int ToBeOverloaded(int input); //with 1 input, integer
    public int ToBeOverloaded(string input); //with 1 input, string
}

答案 3 :(得分:0)

Overload是指具有相同名称和返回类型但同一类中的参数不同的函数。

Shadowing(VB中的Shadows - C#中的New是指更改继承成员的签名。否则,它只是覆盖。阴影可能会导致麻烦,因为它打破了继承。

NewShadows做同样的事情。 似乎在VB中,当你想隐藏一个重载的成员时,你必须隐藏所有的重载。

检查此代码:

Module StartupModule

    Sub Main()
        Dim l1 As Level1 = New Level3
        l1.Print()
        l1.Print(10)

        Console.WriteLine()

        Dim l2 As Level2 = New Level3
        l2.Print()
        l2.Print("20")

        Console.WriteLine()

        Dim l3 As Level3 = New Level3
        l3.Print()
        l3.Print(DateTime.Now)

        Console.ReadLine()
    End Sub


    Public Class Level1
        Public Overloads Sub Print()
            Console.WriteLine("Level1.Print")
        End Sub

        Public Overloads Sub Print(value As Integer)
            Console.WriteLine("Level1.Print(Value)={0}", value)
        End Sub
    End Class

    Public Class Level2
        Inherits Level1

        Public Shadows Sub Print()
            Console.WriteLine("Level2.Print")
        End Sub

        Public Shadows Sub Print(value As String)
            Console.WriteLine("Level2.Print(Value)={0}", value & "1")
        End Sub
    End Class

    Public Class Level3
        Inherits Level2

        Public Shadows Sub Print()
            MyBase.Print()
        End Sub

        Public Shadows Sub Print(value As DateTime)
            Console.WriteLine("Level3.Print(Value)={0}", value)
        End Sub
    End Class

End Module

你的代码中还有一些看似奇怪的东西,这不是你的错。

Class A
    Sub MyMethod()
        Console.WriteLine("A.MyMethod")
    End Sub
    ...
End Class

Class B
    Inherits A
    Overloads Sub MyMethod()
        Console.WriteLine("B.MyMethod")
    End Sub
    ...
End Class

虽然编译器接受了它,MyMethodOverloads中被声明为Class B但实际工作为Shadows。 检查此示例:

Module StartupModule

    Sub Main()
        Dim l1 As Level1 = New Level3
        l1.Print()

        Console.WriteLine()

        Dim l2 As Level2 = New Level3
        l2.Print()

        Console.WriteLine()

        Dim l3 As Level3 = New Level3
        l3.Print()

        Console.ReadLine()
    End Sub


    Public Class Level1
        Public Sub Print()
            Console.WriteLine("Level1.Print")
        End Sub
    End Class

    Public Class Level2
        Inherits Level1

        Public Overloads Sub Print()
            Console.WriteLine("Level2.Print")
        End Sub
    End Class

    Public Class Level3
        Inherits Level2

        Public Overloads Sub Print()
            MyBase.Print()
        End Sub
    End Class

End Module

我认为最大的区别在于,正如我在回答的开头写的那样,VB编译器不能影响重载方法。

答案 4 :(得分:-1)

就c#方法而言,重载意味着通过定义不同的参数来提供相同方法名称的不同版本,例如:

int MethodA(int x){
  return x++;
}

int MethodA(int x, int y){
  return x+y;
}

阴影(就c#方法隐藏而言)是不同的,它意味着改变基类中定义的方法的功能。

public class Parent{
   public int MethodX(int x){
         return x++;
   }
}

public class Child : Parent{
   public new int MethodX(int x){
         return x+2;
   }
}

另请注意,方法隐藏不常用,因为它可能导致不易识别的问题。