关于方法重载的基本问题

时间:2010-07-16 13:00:20

标签: c#

如果我有一个类SubOfParent,它是Parent的子类,还有两个方法:

 public static void doStuff(Parent in) {}

 public static void doStuff(SubOfPArent in) {}

为什么在传递SubOfParent类型对象时会调用 first doStuff?

感谢您对此有任何见解!

9 个答案:

答案 0 :(得分:12)

Parent p = new SubOfParent();
SubOfParent s = new SubOfParent();

doStuff(p); //calls doStuff(Parent in)
doStuff(s); //calls doStuff(SubOfParent in)

//If you're working with a parent but need to call the subclass, you need to upcast it.
dostuff(p as SubOfParent);

答案 1 :(得分:8)

方法重载是在编译时完成的,而不是在运行时完成的,所以你不会看到任何多态性。无论调用代码知道什么类型,都将指定调用哪个方法。

如果要调用第二种方法,可以转换为SubOfPArent类型,或者可以将这些方法放入类中,然后调用它来获取多态性:

public class Parent 
{
  public virtual void doStuff() {}
}

public class SubOfPArent : Parent
{
  public override void doStuff() {}
}

...

Parent obj = getASubOfPArent();
obj.doStuff();

答案 2 :(得分:4)

您可能使用Parent类型的变量调用该方法。

由于在编译时解析了方法重载,编译器只能根据参数的静态编译时类型选择重载。

因此,即使您的变量在运行时实际上可能包含SubOfParent实例,编译器也不会知道,因此会选择第一个重载。

相反,虚拟方法在运行时根据所涉及实例的实际类型进行解析 因此,如果SubOfParent重写了一个虚方法,则在Parent类型的变量上调用该方法将正确调用重写方法(如果该实例实际上是SubOfParent类型。

答案 3 :(得分:2)

我认为您在代码中转换为Parent,或以其他方式提供Parent类型。所以我认为行为是正确的,你期望发生的是不正确的。

两个重载对SubOfParent引用都有效是正确的,但重载决策逻辑会查找更具体的方法,因此应该找到最具体的重载。

SubOfParent p = new SubOfParent();

doStuff((Parent)p); // Calls base overload
doStuff(p); // Calls specific overload

答案 4 :(得分:2)

如果您对使用dynamic关键字感到满意,可以考虑这样做:

private static void doStuffImpl(Parent obj) {
   Console.WriteLine("I'm a Parent!");
}

private static void doStuffImpl(SubOfParent obj) {
   Console.WriteLine("I'm a Sub of Parent!");
}

public static void doStuff(Parent obj) {
    try {
      doStuffImpl(obj as dynamic);
    }
    catch (RuntimeBinderException ex) {
        // Not implemented !
    }
}

如果你有很多子类,它会很有用。

doStuffImpl(obj as dynamic);将在运行时进行评估。 doStuffImpl将使用obj的真实类型进行调用。

答案 5 :(得分:1)

方法重载在编译时完成,因此在编译时依赖于静态类型来确定重载方法。在您的示例中,可能会发生以下情况:

public static void Main(string[] args)
{
    SubOfParent a = new SubOfParent();
    doStuff(a); // doStuff(SubOfParent) is called
}

编译时的静态类型是SubOfParent,因此将调用预期的重载。

public static void Main(string[] args)
{
    Parent a = new SubOfParent();
    doStuff(a); // doStuff(Parent) is called
}

静态类型(声明类型)是Parent。在这种情况下,无论a.GetType()在运行时返回的值如何,都将选择其他重载版本。

答案 6 :(得分:0)

要调用doStuff(SubOfPArent),你需要这样的东西:

SubOfPArent.doStuff(new SubOfPArent());

但我认为你直到运行时才知道类型吗?

Tster说的更优雅。我认为这是正确的。

答案 7 :(得分:0)

基本上,编译器根据该对象的声明的类型解析在对象上调用的方法(即,当该对象作为参数传递时)。因此,如果您将变量键入为Parent并将其传递给doStuff,则编译器会将该方法调用解析为带有Parent的重载,即使在运行时该对象变为成为SubOfParent

方法通过对象调用(即类的实例方法)在运行时表现出多态性:执行的方法基于对象的实际类型。

所以,如果你有这个:

class Parent
{
    public virtual void doStuff() { }
}

class SubOfParent : Parent
{
    public override void doStuff() { }
}

Parent p  = new SubOfParent();
p.doStuff();

然后代码可以按预期工作。

答案 8 :(得分:0)

你可以重载功能 通过声明具有相同名称和不同参数的多个函数