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