C# 方法重载的基本问题

C# 方法重载的基本问题,c#,C#,如果我有一个类SubOfParent,它是父类的子类,并且有两个方法: public static void doStuff(Parent in) {} public static void doStuff(SubOfPArent in) {} 为什么在传递SubOfParent类型对象时会调用第一个doStuff 谢谢你对这方面的任何见解 方法重载是在编译时完成的,而不是在运行时,所以您不会看到任何多态性。无论调用代码知道什么类型,都将指定调用哪个方法 如果要调用第二个方法,可以强制转

如果我有一个类SubOfParent,它是父类的子类,并且有两个方法:

 public static void doStuff(Parent in) {}

 public static void doStuff(SubOfPArent in) {}
为什么在传递SubOfParent类型对象时会调用第一个doStuff


谢谢你对这方面的任何见解

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

如果要调用第二个方法,可以强制转换为类型
SubOfPArent
,也可以将这些方法放入类中,然后调用它以获得多态性:

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

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


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

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

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

SubOfParent p = new SubOfParent();

doStuff((Parent)p); // Calls base overload
doStuff(p); // Calls specific overload
相反,虚拟方法在运行时根据所涉及实例的实际类型进行解析。
因此,had
SubOfParent
重写了一个虚拟方法,对类型为
Parent
的变量调用该方法将正确地调用被重写的方法,如果实例实际上是类型为
SubOfParent

要调用doStuff(SubOfParent in),您需要这样的东西:

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 !
    }
}
doStuff(新的SubOfPArent())

但是我想你直到运行时才知道类型,对吗


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

基本上,编译器根据对象的声明类型解析对象上调用的方法(即,当对象作为参数传递时)。因此,如果将一个变量类型化为
Parent
,并将其传递给
doStuff
,编译器将把该方法调用解析为采用
Parent
的重载,即使在运行时该对象被证明是
子父对象

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

如果你有这个:

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

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

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

然后代码将如您所期望的那样工作。

我认为您正在代码中转换为
父级
,或者提供一个
父级
类型。所以我认为这种行为是正确的,而你所期望的是错误的

正确的是,这两个重载对于
SubOfParent
引用都有效,但是重载解析逻辑将查找更具体的方法,因此应该查找最具体的重载

SubOfParent p = new SubOfParent();

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

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

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
}

静态类型(声明时的类型)是父类型。在这种情况下,将选择另一个重载版本,不管值A.GETType()是否在运行时返回。

< P>如果您可以使用<代码>动态< /COD>关键字,您可以考虑这样做:

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 !
    }
}
如果您有很多子类,它可能会很有用

dostuffinpl(obj为动态)将在运行时进行计算
dostuffinpl
将使用
obj
的实型调用。

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

请发布代码,从这个上下文中没有人可以idea@Yakeen,这里有足够的代码来知道哪里出了问题。@sardukar:你确定函数是静态的吗?我肯定传递了SubOfParent。调用这两个函数的方法有if(a.GetType()==typeof(SubOfParent)){doStuff(a);}else{doStuff(a);}和通过代码调试,它肯定会通过第一个doStuff(a)。啊,如果您必须进行类型检查,那么是的,运行时类型可能是
SubOfParent
,但我怀疑编译时类型是
Parent
——在C中,重载选择是在编译时定义的。这就是函数重载和多次分派之间的区别。@sardaukar:因为
a
变量被声明为
Parent
,编译器将始终调用第一个重载。如果
Parent
SubOfParent
是用户定义的类,是的,它会工作。问题是关于静态函数,而不是实例函数。@apoorv020 tster仍然正确回答了问题。虽然静态方法重载的处理方式确实与实例方法略有不同,但在这种情况下没有区别。@apoorv020,这就是我说他可以移动函数的原因。显然,我建议他改变代码的结构方式。在这个例子中,p的类型显然是SubOfParent,但情况并非总是如此。为了避免doStuff中出现任何意外情况,最好向上投射,检查null,然后进行调用。SubOfParent SubOfParent=p作为SubOfParent;if(subOfParent!=null)doStuff(subOfParent);这在某些情况下是有道理的,但当试图在策略模式中使用重载时,它失败得很惨;例如,如果指定了一个派生类型的父类型变量,则不能让代码自动在SubOfParent和SubOfParent2重载之间进行选择。