当我使用TemplateA类型的参数调用EntryPoint时,我总是收到异常,因为总是调用第一个重载。
我所期望的是,由于动态绑定,将调用最具体的方法(第二次重载)。
有什么想法吗?
private object _obj;
public void EntryPoint(object p)
{
myFunc(p);
}
//first overload
private void myFunc(object container)
{
throw new NotImplementedException();
}
//second overload
private void myFunc(TemplateA template)
{
_obj = new ObjTypeA(template);
}
//third overload
private void myFunc(TemplateB template)
{
_obj = new ObjTypeB(template);
}
答案 0 :(得分:4)
我期望发生的是,由于动态绑定,将调用最具体的方法(第二次重载)。
你在哪里看到动态绑定?变量的静态类型是object
。除非您直接调用上的虚拟方法,否则不会发生动态调度。在编译时完全静态地解决了重载。
Eric Lippert有一篇相关的博客文章:Double Your Dispatch, Double Your Fun。
答案 1 :(得分:2)
当您使用EntryPoint()
类型的参数调用TemplateA
时,会将其转换为object
。因此,对myFunc(p)
的后续静态绑定调用将使用object
类型的参数进行。
答案 2 :(得分:1)
如果您使用dynamic
而不是object
,则可以在C#4.0中执行此操作。如果您想尝试一下,请下载Visual Studio 2010 Beta。在此之前,编译器会根据参数的编译时类型选择要调用的方法。
从您的问题中不清楚您是否了解普通的单调度多态,因为它可以解决您的示例问题。
class TemplateBase
{
public virtual object MyFunc()
{
throw new NotImplementedException();
}
}
class TemplateA : TemplateBase
{
public override object MyFunc()
{
return new ObjTypeA(this);
}
}
class TemplateB : TemplateBase
{
public override object MyFunc()
{
return new ObjTypeB(this);
}
}
其他地方:
private object _obj;
public void EntryPoint(TemplateBase p)
{
_obj = p.MyFunc();
}
当您无法修改TemplateN
类时,还有其他选择。最简单的方法是EntryPoint
方法可以访问从Dictionary
到某个委托的Type
映射。
Dictionary<Type, Func<object, object>> _myFuncs;
_myFuncs.Add(typeof(TemplateA), o => new ObjTypeA((TemplateA)o));
_myFuncs.Add(typeof(TemplateB), o => new ObjTypeB((TemplateA)o));
然后它可以查找委托来执行传递给它的对象类型。
Func<object, object> f = _myFuncs[p.GetType()];
_obj = f(p);
但是如果你想模仿虚函数的确切运作方式,你需要注意继承层次结构。
答案 3 :(得分:0)
我认为在EntryPoint上下文中,编译器知道应该调用第一个重载,因为它是静态绑定而不是动态