Обобщения и реализация IComparable

Я очень новичок в дженериках, и я пытаюсь написать простой класс, который будет универсальным, но также позволит сортировать некоторое описание в строковой переменной-члене.

На данный момент у меня есть базовый класс, но когда я пытаюсь реализовать член интерфейса CompareTo(), я получаю сообщение об ошибке вверху, сообщающее мне, что он не реализован. В чем проблема?

using System;

namespace GenericsPracticeConsole.Types
{
    class SortableGenericType<T> : IComparable
    {
        private T t;
        private string stringName;

        public T name
        {
            get { return t; }
            set { t = value; }
        }

        public int CompareTo(SortableGenericType<T> ourObject)
        {
            return stringName.CompareTo(ourObject.stringName);
        }
    }
}

person CSharpened    schedule 01.02.2012    source источник


Ответы (2)


Есть два интерфейса IComparable и IComparable<U>. IComparable является более старым (появившимся до дженериков), который требует сравнения экземпляров с произвольными объектами. IComparable<U> требует, чтобы экземпляры сравнивались с экземплярами U. Если вы хотите объявить, что вы будете сравнивать экземпляры SortableGenericType в полях stringName, это то, что вы должны сделать:

class SortableGenericType<T> : IComparable<SortableGenericType<T>>
{
   //
}

Если вы также хотите реализовать IComparable:

   class SortableGenericType<T> : IComparable, IComparable<SortableGenericType<T>> 
   {
      private string stringName;
      public T name { get; set; }

      public int CompareTo(SortableGenericType<T> ourObject)
      {
         //I forgot to add this statement:
         if(ourObject == null) 
             return -1; 
         return stringName.CompareTo(ourObject.stringName);
      }

      public int CompareTo(object obj)
      {
         if (obj.GetType() != GetType())
            return -1;
         return CompareTo(obj as SortableGenericType<T>);
      }
   }

Если бы ваш класс был коллекцией, которая будет содержать элементы типа T, и вам нужно, чтобы эти элементы можно было заказать (это не то, что вы спрашиваете, но это наиболее распространенный сценарий), вам потребуется, чтобы T было IComparable<T> :

   class SomeCollection<T> where T : IComparable<T>
   {
      private List<T> items; 

      private void Sort()
      {
         //
         T item1;
         T item2;
         if(item1.CompareTo(item2) < 0)
         {
            //bla bla
         }
      }
   }
person Ali Ferhat    schedule 01.02.2012
comment
Я бы не стал делать if (obj.GetType() != GetType()) return -1;, потому что тогда ваше сравнение больше не будет антисимметричным или рефлексивным. - person porges; 01.02.2012
comment
Истинный. Но я не знаю, что мне делать в таком случае. Что бы вы предложили? - person Ali Ferhat; 01.02.2012
comment
Во второй функции CompareTo вы используете следующую строку: return CompareTo(obj as SortableGenericType‹T›); Сравнивает ли эта строка неявно текущий объект, который у нас есть, с переданным без фактической ссылки на текущий элемент в строке? - person CSharpened; 01.02.2012
comment
Ok. Итак, мой первоначальный вопрос был о строке: return CompareTo(obj as SortableGenericType‹T›); Сравнивает ли эта строка в основном текущий объект, который был вызван, с переданным объектом, т.е. myInstance.CompareTo(passedInstance) только без фактического указания this.CompareTo или подобного? Извините, что спрашиваю еще раз, но я хотел бы прояснить, что я знаю, что происходит, прежде чем продолжить. Спасибо за помощь. - person CSharpened; 01.02.2012
comment
@CSharpened: ваше предложение не работает, если кто-то реализует подкласс SubSortableGType и передает аргумент типа SubSortableGType в CompareTo. Но это напоминает мне, что я забыл случай, когда ourObject может быть нулевым, я добавил строку для этого случая. Спасибо. obj as SortableGenericType<T> приводит obj к SortableGenericType<T>, в случае неудачи результат будет нулевым, поэтому, если вы передаете аргумент несвязанного типа, CompareTo будет вызываться с нулевым значением, и результат всегда будет меньше, чем. Трудно предложить что-то лучшее, не зная больше о вариантах использования. - person Ali Ferhat; 01.02.2012
comment
Извините, Али, я думаю, вы неправильно понимаете, о чем я спрашиваю. Все, что я прошу, это то, что строка «return CompareTo (obj as SortableGenericType‹T›);» эффективно делать thisObject.CompareTo(passedObject) в псевдокоде. Извините, если я не был ясен. Все, что я хочу знать, это так ли это, поскольку нет упоминания об объекте, для которого мы вызвали функцию. - person CSharpened; 01.02.2012
comment
obj as SortableGenericType<T> приводит объект obj к типу SortableGenericType<T> Мы знаем, что приведение будет успешным, потому что мы проверили это в строке выше. Таким образом, оператор вызывает другой метод CompareTo, тот, что имеет сигнатуру public int CompareTo(SortableGenericType<T> ourObject), и возвращает результат на основе полей stringName. Отвечает ли это на ваш вопрос? - person Ali Ferhat; 01.02.2012
comment
@Ali: я не уверен, что для этого лучше всего. Я, наверное, просто не стал бы реализовывать IComparable :) - person porges; 02.02.2012
comment
@AliFerhat: нулевой результат от CompareTo или Compare не должен интерпретироваться как означающий, что сравниваемые элементы действительно равны, а скорее как то, что они ранжируются одинаково по отношению ко всем другим объектам, без ранжирования по отношению друг к другу. Обычно это означает, что только один класс в цепочке наследования должен реализовывать неуниверсальное IComparable, а все производные классы должны использовать унаследованное определение. Производные классы могут реализовывать IComparable<theirOwnType>, но должны использовать унаследованные определения для IComparable<baseTypes>. - person supercat; 19.04.2012
comment
Проверка GetType() просто... неверна. Должно быть так: public int CompareTo(object obj) { var that = obj as SortableGenericType<T>; if (that == null) return -1; return this.CompareTo(that); } - person osexpert; 21.03.2019

IComparable определяет метод public int CompareTo(object obj). Обратите внимание на тип параметра — это object, а не ваш собственный тип. Вот почему вы на самом деле не реализуете интерфейс.

Что вам нужно сделать, так это реализовать IComparable<SortableGenericType<T>>

person Avner Shahar-Kashtan    schedule 01.02.2012
comment
Идеально. Большое спасибо. Я предположил, что, поскольку мой тип был самостоятельным объектом, это было бы нормально. Спасибо за объяснение. - person CSharpened; 01.02.2012
comment
Ваш тип — это объект, но это конкретный объект. IComparable позволяет сравнивать ваш объект с ЛЮБЫМ объектом, а не только с вашим конкретным типом. - person Avner Shahar-Kashtan; 01.02.2012