#c# #oop #polymorphism #overloading
#c# #ооп #полиморфизм #перегрузка
Вопрос:
Здесь полный вопрос ОО новичка. У меня есть эти два метода в классе
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 наследует сеанс)
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; }
}
Комментарии:
1. Есть ли конкретная причина, по которой вы вводите как ‘var’, а не ‘LateSession’?
2. @acron, в чем причина не вводить
var
?3.
var
!=dynamic
если это ваша причина против его использования. Это ярлык программиста. Компилятор по-прежнему применяет строгую типизацию и будет жаловаться, если не сможет определить фактический тип.4. @acron, использование var здесь полностью эквивалентно использованию полного имени типа, это просто синтактический сахар…
5. @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», и жестко кодирует вызов метода с помощью аргумента сеанса.
Во втором примере аналогично компилятор генерирует жестко запрограммированный вызов другого метода.
В других языках вызов метода является «динамическим», что означает, что во время выполнения рассматриваются фактические типы. Методы, полиморфные по своим аргументам, называются «мультиметодами» (они полиморфны не только по классу, в котором они определены, но и по аргументам, следовательно, «мульти») (Редактировать: исправлены опечатки)
Комментарии:
1. Хорошее объяснение, я никогда этого не знал. Дальнейший поиск в Google показал, что ни C #, ни Java не допускают множественную отправку, но Lisp и Python допускают.
2. Но на самом деле, в этом случае все должно работать так, как ожидалось, поскольку тип известен во время компиляции, и должна быть вызвана правильная перегрузка. Вероятно, есть какая-то другая проблема, которая не очевидна из показанного примера…
3. Тип не «действительно» известен во время компиляции. Рассмотрим переменную, вводимую через параметр. Я только поместил «новый» там, чтобы мы, как читатели, знали, что происходит; 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)
перегрузку и учитывать LateSession при (Session, SessionViewModel)
перегрузке, например:
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 # нет множественной отправки, однако вы можете реализовать двойную отправку, используя шаблон Visitor.
Ответ №5:
Какой тип dbSession
после этого присваивания? Я бы предположил, что это то, что вы ожидаете, но это может быть Session
.
Вам действительно нужно перегружать этот метод как дочерним, так и родительским классом по отдельности? Это кажется странным случаем, когда вам понадобятся оба, и, вероятно, приведет к путанице.
Комментарии:
1. Я поместил это там просто в качестве иллюстрации. Итак, dbSession имеет тип LateSession. Во время выполнения в моем коде я вижу, что dbSession имеет тип LateSession, а базовый класс — Session. Я хочу сделать это таким образом, чтобы у меня было разное поведение для разных типов. В противном случае я прибегну к очень неприятному переключению.