【问题标题】: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,该语言确实使用它首先找到的与参数匹配的方法。

标签: c# oop polymorphism overloading


【解决方案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。我想这样做,所以我对不同类型有不同的行为。否则我会求助于超级讨厌的开关。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-06-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多