Разрешение метода в Comparer - PullRequest
       3

Разрешение метода в Comparer

1 голос
/ 05 августа 2010

рассмотрим следующую базовую схему классов:

public class Base : IComparable<Base>
{
  public int CompareTo(Base other)
  {
    //Do comparison
  }
}

public class Derived : Base, IComparable<Derived>
{
  public int CompareTo(Derived other)
  {
    //Do comparison
  }  
}

public class BaseComparer : IComparer<Base>
{
  public int Compare(Base x, Base y)
  {
   return x.CompareTo(y);
  }
}

, а затем использовать их следующим образом:

List<Base> thingies = new List<Base>
{
  new Base(),
  new Derived(),
  new Derived()
};

thingies.Sort(new BaseComparer());

Я ожидал, что Comparer вызовет метод Derived.CompareTo в тех ситуациях, когда его параметры x и y являются производными экземплярами.

Однако это не тот случай, и вместо этого вызывается Base.CompareTo, и я продолжаю задаваться вопросом, почему. Кажется, я не могу вывести это поведение из моего базового понимания правил разрешения перегрузки, как описано в спецификации языка C #.

Может кто-нибудь пролить свет на это для меня?

Ответы [ 3 ]

5 голосов
/ 05 августа 2010

Base ничего не знает о своих производных классах - поэтому в Base есть только один CompareTo метод, и он вызывается безоговорочно.

Дело в том, что разрешение перегрузки происходит в время компиляции , когда нет никакой информации о фактическом типе Base доступных ссылок. Вам необходимо переопределить метод в Derived, а не перегрузить it:

public class Derived : Base
{
  public override int CompareTo(Base other)
  {
    //Do comparison
  }  
}

И дополнительно отметьте Base.CompareTo метод virtual.

Обратите внимание, что это больше не реализует IComparable<Derived>. Вы можете также сделать это, но для вашей цели это не имеет отношения.

1 голос
/ 05 августа 2010

IComparable<Base> и IComparable<Derived> - это два разных типа, поэтому два метода CompareTo в Derived отображаются на два разных слота. CompareTo вызывается BaseComparer, вызывает метод IComparable<Base>. Вы можете обозначить CompareTo(Base) в Base как virtual и переопределить его в Derived, чтобы получить (частично) ожидаемое поведение.

public class Base : IComparable<Base>
{
    public virtual int CompareTo(Base other)
    {
        // do comparison
    }
}

public class Derived : Base, IComparable<Derived>
{
    public int CompareTo(Derived other)
    {
        // do comparison
    }

    public override int CompareTo(Base other)
    {
        if (other is Derived)
            return CompareTo((Derived) other);
        return base.CompareTo(other);
    }
}
1 голос
/ 05 августа 2010

Разрешение перегрузки не то, что здесь происходит.У вас есть два независимых метода: их полные имена IComparable<Base>.CompareTo и IComparable<Derived>.CompareTo.

Единственный, который BaseComparer знает, как вызывать, это IComparable<Base>.CompareTo.Он ничего не знает о IComparable<Derived>.

. Имеет ли смысл в вашем приложении сравнивать Base с Derived - то есть можно сказать, что Base стоит до или послеDerived?

  • Если это так, вам лучше остаться только с IComparable<Base> или даже неуниверсальным IComparable и быть готовым проверять типы в подклассах
  • Если нет, вам следует подумать о том, чтобы сделать Base абстрактным, и реализовать только IComparable<T> на листовых классах
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...