C#与VB.Net的比较;s Shadowing和[Overloading(不更改参数)]之间的区别

本文关键字:参数 区别 之间 Overloading Net VB 比较 Shadowing | 更新日期: 2023-09-27 18:30:12

很抱歉问了这么长的问题,但我对C#有点陌生(我曾经使用VB.Net)

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

现在,在VB.Net中,Shadowing(使用关键字Shadows)和Overloading

  • 当使用Shadows时,它会对具有相同名称的每个方法(无论参数如何)进行阴影处理,使其仅成为一个方法(阴影方法)
  • 当使用具有相同参数的重载时,它只重载(阴影)具有相同名称和参数的方法

考虑这个代码:

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

While:

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#中重载和阴影没有区别!!

有人能解释为什么存在这种差异吗?

感谢

C#与VB.Net的比较;s Shadowing和[Overloading(不更改参数)]之间的区别

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

什么是继承

当一个类型从另一个类型继承时,基类型的可继承成员也是派生类型的成员。大多数成员是可继承的;少数人,比如构造器,却不是。

所有成员?甚至是私人的?

是的。私人成员是继承的。按名字查找它们可能不合法,但它们仍然是继承的。

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

当一个类型中有两个同名但签名不同的方法时,方法被重载。(就本讨论而言,方法的签名包括其名称、通用arity、参数数量和参数类型。)

如果我们有一个类型D,它有两个重载成员M(X)和M(Y),那么其中一个从基类型B继承,另一个在D中声明是完全可以的。它们仍然是重载。

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

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

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

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

还有更多涉及通用方法和决胜局的规则与本次讨论无关。

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

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

特别是,如果隐藏方法是一种适用的方法,则重载解析将选择隐藏方法而不是任何基类型成员,因为我们已经知道,重载解析会丢弃不属于最派生类型的成员。由于隐藏方法总是比隐藏方法具有更派生的类型,因此它总是获胜——当然前提是它是可访问的。

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

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

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

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

VB中成员隐藏的工作规则是否与C#中的隐藏规则略有不同?

是的。

为什么?

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

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

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

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

在这种情况下,在C#中的方法上使用New关键字不会进行"阴影化"。它用于方法隐藏。

检查此

在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
}

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

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

CCD_ 9和CCD_。似乎在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

尽管编译器接受它,但MyMethodClass B中被声明为Overloads,但实际上是作为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编译器不能对重载方法进行阴影处理。

就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;
   }
}

还要注意的是,方法隐藏并不常用,因为它可能会导致不容易识别的问题。