C# vs VB.Net,Shadowing 和 [Overloading (without changing the arguments)] 有什么区别

C# vs VB.Net, what's the difference between Shadowing and [Overloading (without changing the arguments)]

抱歉问了这么长的问题,但我是 C# 的新手(我以前使用 VB.Net)

我完全理解 OverridingOverloading 在 VB.Net 和 C# 中的区别.. 所以没有问题压倒一切。

现在,在 VB.Net 中,Shadowing(使用关键字 Shadows)和 之间存在差异Overloading(使用关键字Overloads'with the same arguments')如下:

考虑这段代码:

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# 中,Shadowing(使用关键字 New)和 Overloading(同名& 参数)!

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

obj.MyMethod2(10);

将 return>> 'A.MyMethod2 (x)'

看起来 C# 中的重载和隐藏之间没有区别!!

谁能解释为什么存在这种差异?

谢谢

勾选this

在 C# 中,阴影 意味着您可以完全替换该项目。例如,您可以 shadow 父 class 中名为 ToBeShadowedfield 并成为 子class中的方法ToBeShadowed()。在此过程中,无论何时使用父项 class,该项目都将是 字段,但如果您使用子项 class,该项目将是 ]方法。因此,阴影允许您完全改变同名物品的性质。

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

重载,但是完全不同于阴影。例如,您 不能 将字段重载 到方法。每个重载都必须具有相同的 return,尽管它可能具有不同的输入参数。因此,重载就像在不改变项目性质的情况下为输入参数添加更多可能性。但是阴影可以做到。

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
}

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

在这种情况下,在 C# 中的方法上使用 New 关键字不会执行 "shadowing"。它用于 method hiding.

在c#中方法重载是指通过定义不同的参数来提供相同方法名的不同版本,例如:

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

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

阴影(在 c# 方法隐藏方面)是不同的,它意味着改变基 class.e.g.

中定义的方法的功能
public class Parent{
   public int MethodX(int x){
         return x++;
   }
}

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

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

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

What is inheritance?

当一种类型从另一种继承时,基类型的可继承成员也是派生类型的成员。大多数成员是可继承的;一些,比如构造函数,不是。

All members? Even private ones?

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

In C#, what is overloading a method?

当一种方法有两种同名但签名不同的方法时,该方法被重载。 (出于本次讨论的目的,方法的签名由其名称、泛型数量、参数数量和参数类型组成。)

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

In C#, how are overloads resolved?

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

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

如果剩下一种方法,则它获胜。否则,每对适用的方法都会被评估,看看一个是否比另一个更好地匹配参数;任何比另一种更糟糕的方法都将被淘汰。如果此过程产生唯一的最佳方法,则它获胜。

还有更多涉及泛型方法和决胜局的规则与此讨论无关。

In C#, what is hiding by name for methods?

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

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

In C# how do we mark a member as hiding by name?

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

In C#, what happens if overload resolution cannot pick a hiding method because it is inapplicable or inaccessible?

那么通常的重载决议规则适用。隐藏方法不适用,因此立即从正在考虑的方法集中删除。这可能意味着在派生类型中声明的任何方法都不适用,因此基 class 的成员可能是 在最派生类型中声明的适用方法.

Is the rule for how member shadowing works in VB slightly different than the hiding rules in C#?

是的。

Why?

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

So what is the difference between hiding a method and overloading a method in C#?

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

Overload 是当您有一个具有相同名称和 return 类型但相同 class.

中的不同参数的函数时

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

NewShadows 做同样的事情。 貌似在VB想隐藏一个重载的成员,就得shadow所有的重载。

检查此代码:

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 编译器无法隐藏重载方法。