为啥不根据参数类型调用最具体的方法
Posted
技术标签:
【中文标题】为啥不根据参数类型调用最具体的方法【英文标题】:Why isn't the most specific method called based on type of parameter为什么不根据参数类型调用最具体的方法 【发布时间】:2011-08-24 23:18:27 【问题描述】:这里的总 OO 菜鸟问题。我在一个类中有这两种方法
private void StoreSessionSpecific(LateSession dbSession, SessionViewModel session)
session.LateSessionViewModel.Guidelines = dbSession.Guidelines.ToList();
private void StoreSessionSpecific(Session dbSession, SessionViewModel session )
// nothing to do yet...
当我调用 StoreSessionSpecific 时,dbSession 的类型为 LateSession(LateSession 继承 Session)
var dbSession = new LateSession();
StoreSessionSpecific(dbSession, session);
我预计排名靠前的会被调用。由于 dbSession 是 LateSession 类型。
@Paolo Tedesco 这就是类的定义方式。
public class Session
public int ID get; set;
public int SessionTypeId get; set;
public virtual SessionType SessionType get; set;
[Required]
public DateTime StartTime get; set;
[Required]
public DateTime EndTime get; set;
// Session duration in minutes
// public int SessionDuration get; set;
public virtual ICollection<Attendee> Attendees get; set;
public class LateSession : Session
public int MaxCriticalIncidentsPerUser get; set;
public int MaxResultCriticalIncidents get; set;
public virtual ICollection<Guideline> Guidelines get; set;
【问题讨论】:
您输入“var”而不是“LateSession”是否有特定原因? @acron,不输入var
的原因是什么?
var
!= dynamic
如果这是您反对使用它的原因。这是程序员的捷径。编译器仍然强制执行强类型,如果它不能确定实际类型会报错。
@acron,这里使用 var 完全等同于使用全类型名,只是语法糖...
@Michail,该语言确实不使用它首先找到的与参数匹配的方法。
【参考方案1】:
嗯,您的假设是合理的,并且有些语言的工作方式与您的想法一样。
你的代码是这样的吗:
Session s = new LateSession(); // the compiler only "knows" that s is of type Session
StoreSessionSpecific(s);
或者看起来像这样:
LateSession ls = new LateSession(); // the compiler knows that ls is in fact a LateSession
StoreSessionSpecific(ls);
在第一个示例中,编译器假装不知道“s”的实际类型,并使用 Session 参数对方法的调用进行硬编码。 在第二个示例中,编译器同样会生成对另一个方法的硬编码调用。
在其他语言中,方法调用是“动态的”,这意味着在运行时会考虑实际类型。在其参数上具有多态性的方法称为“多方法”(它们不仅在定义它们的类上是多态的,而且在参数上也是多态的,因此是“多”的) (编辑:修正错别字)
【讨论】:
一个很好的解释,我从来不知道这个。进一步的谷歌搜索显示,C# 和 Java 都不允许多重分派,但 Lisp 和 Python 允许。 但实际上,在这种情况下,事情应该按预期工作,因为在编译时类型是已知的,并且应该调用正确的重载。可能还有一些其他问题在显示的示例中并不明显...... 该类型在编译时不是“真正”知道的。考虑通过参数传递的变量。我只把“新”放在那里,我们作为读者都知道发生了什么;D【参考方案2】:我认为问题出在您代码的其他地方。如果您尝试这个示例,一切都会按预期进行:
class Base
class Derived : Base
class Something
private void DoSomething(Base b)
Console.WriteLine("DoSomething - Base");
private void DoSomething(Derived d)
Console.WriteLine("DoSomething - Derived");
public void Test()
var d = new Derived();
DoSomething(d);
static class Program
static void Main(params string[] args)
Something something = new Something();
something.Test();
你能发布一个完整的例子吗?可能是类定义有问题...
【讨论】:
【参考方案3】:我很抱歉不知道发生这种情况的具体原因为什么,但我知道如何解决它。
尝试失去(LateSession, SessionViewModel)
重载,并在(Session, SessionViewModel)
重载中考虑LateSession,如:
private void StoreSessionSpecific(Session dbSession, SessionViewModel session )
if (dbSession is LateSession)
// handle as LateSession
else
// handle as base-class Session
【讨论】:
【参考方案4】:正如 Angel O'Sphere 所说,C# 没有多重分派,但是您可以使用访问者模式实现双重分派。
http://en.wikipedia.org/wiki/Visitor_pattern
【讨论】:
【参考方案5】:分配后dbSession
的类型是什么?我会假设这是您所期望的,但它可能是 Session
。
另外,你真的需要用子类和父类重载这个方法吗?这似乎是一个奇怪的情况,您需要两者,并且可能会导致混乱。
【讨论】:
我把它放在那里只是为了说明。所以 dbSession 属于 LateSession 类型。在我的代码中运行时,我看到 dbSession 的类型是 LateSession,而基类是 Session。我想这样做,所以我对不同类型有不同的行为。否则我会求助于超级讨厌的开关。以上是关于为啥不根据参数类型调用最具体的方法的主要内容,如果未能解决你的问题,请参考以下文章