Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > .NET для новичков > Сортировка объеков


Автор: Лена 24.10.2007, 17:43
Допустим есть массив пользовательских объектов:
//в Main
Car[]myAutos = new Car[5];
myAutos[0] = new Car("Rusty", 80,1);
myAutos[1] = new Car("mary", 40,234);
//и т.д.

Чтобы была возможность отсортировать методом Array.Sort(myAutos); надо добавить в класс Сar поддрежку интрефейса IComparable:

Код

public class Car: IComparable
{
.....
//Планируется сортировка по свойству carID описанному в классе Car
//Реализация метода интрефейса:
int IComparable.CompareTo(oblect obj)
  {
  Car temp = (Car)obj;
  if(this.carID > temp.carID)
  return 1;
  if(this.carID < temp.carID)
  return -1;
  else 0;
  }
.....
}

После такого объявления можно использовать Array.Sort(myAutos);

Объсните почему в классе Car надо писать так:
int IComparable.CompareTo(oblect obj)?
Можно ли заменить на:
public int CompareTo(oblect obj) ???


Автор: tol05 24.10.2007, 18:03
Цитата(Лена @  24.10.2007,  17:43 Найти цитируемый пост)
Объсните почему в классе Car надо писать так:
int IComparable.CompareTo(oblect obj)?

потому что ты используешь явную реализацию интерфейса IComparable. Если бы ты писала 
Код

int CompareTo(oblect obj)
{
 ...
}
то тогда можно было бы использовать вызов обычного метода класса Car.CompareTo(myObj)
Но это не совсем хорошо с точки зрения полиморфизма.

Цитата(Лена @  24.10.2007,  17:43 Найти цитируемый пост)
Можно ли заменить на:
public IComparable CompareTo(oblect obj) ???

нельзя. CompareTo интерфейса IComparable должен возвращать int, а не IComparable smile Это общепринятое соглашение для стандарной сортировки (обязательное условие). 
Иначе прийдется тебе по-своему определять метод Sort(), работающий не с int, а с IComparable, в чем нет никакого смысла - это ходьба по кругу...

Если ты уберешь наследование от IComparable, тогда можешь писать... Просто создашь метод Car.CompareTo, который не имеет ничего общего с сортировкой.

Автор: Лена 24.10.2007, 18:20
Про вовращаемое значение int я поняла и исправила, но вы уже ответили. smile 
Тогда такой вопрос:
Например есть интрефейс ICloneable он имеет метод Сlone.

Вот есть такой рабочий код:
Код

public class Point : ICloneable
{
..........
//реализация метода интерфейса
public object Clone()
{
return new Point(this.x, this.y);
}
..........
}


Почему же в этом случае автор не написал:
object ICloneable.Clone() ?

Все таки будет работать сортировка в первом коде если класс Car будет иметь один метод public int CompareTo(oblect obj) и унаследован от IComparable?

Автор: OLEG_NET 24.10.2007, 18:33
потому что был создан один метод Clone и он принадлежит интерфейсу ,если ты захочешь чтобы у тебя этот метод мог наследоваться в других классах ,ты должна будешь написать свой метод,так как по-умолчанию методы интерфейса невиртуальные,и тогда будешь ставить перед Clone имя интерфейса,а еще это нужно для того чтобы явно вызывать объект интерфейса 

Автор: Лена 24.10.2007, 18:55
Из того, что я поняла имя интрефейса используется при нотации метода (например, int IComparable.CompareTo(oblect obj)) только для того, чтобы в коде Main можно было вызвать такой метод только через интрефейсную ссылку. Также удобно использовать эту натацию при множественном наследовании интрефейсов с одинаковыми именами у методов, чтобы они не перекрывали друг друга.

Делаю ли я правильный вывод?:
Сортировка в первом коде будет работать и в случае такого обявления int IComparable.CompareTo(oblect obj) и в случае если это объявление будет заменено на public int CompareTo(oblect obj).  Ошибки не будет. smile 

Автор: OLEG_NET 24.10.2007, 20:54
Вывод правильный! smile 

Автор: kurzon 24.10.2007, 21:58
Код

using System;
using System.Collections.Generic;
using System.Text;

namespace Con_Sort
{
   


    struct Book
    {
        public Book(string author, int year)
        {
            this._year = year;
            this._author = author;
        }

        private int _year;

        public int Year
        {
            get { return this._year; }
            set { this._year = value; }
        }

        private string _author;

        public string Author
        {
            get { return this._author; }
            set { this._author = value; }
        }

        public override string ToString()
        {
            return String.Format("Название книги :{0}, Год :{1}", Author, Year);
        }
    }
 class Teenager
    {
        private static Random random = new Random();
        private static readonly string[] messages = new string[6]
            { 
                "Троесент!", 
                "Ватсон!", 
                "Фаронов!", 
                "Шилд!", 
                "Агуров!", 
                "Глинський!" 
            };

        public static string Complain()
        {
            return messages[random.Next(messages.Length)];
        }
    }

    class Program
    {
        static void PrintBookTitles(Book[] books)
        {
            foreach (Book book in books)
            {
                Console.WriteLine(book);
            }
        }

        static void Main(string[] args)
        {
            Book[] books = new Book[10];
            Random random = new Random();

            for (int i = 0; i < books.Length; i++)
            {
                books[i] = new Book(Teenager.Complain(), random.Next(2007));
            }

            PrintBookTitles(books);
            Console.ReadLine();

            Array.Sort(books, delegate(Book a, Book b)
                    {
                        return a.Year.CompareTo(b.Year);
                    });
        
            Console.WriteLine("После сортировки:");

            PrintBookTitles(books);
            Console.ReadLine();
        }

        }
    }



Автор: tol05 24.10.2007, 23:44
kurzon ударил кодом по балаболам smile

Цитата(Лена @  24.10.2007,  18:55 Найти цитируемый пост)
Из того, что я поняла имя интрефейса используется при нотации метода (например, int IComparable.CompareTo(oblect obj)) только для того, чтобы в коде Main можно было вызвать такой метод только через интрефейсную ссылку.

не только поэтому. То, что можно вызывать из Main интерфейсную ссылку - это следствие. А причина - в том, что сами библиотеки .Net (стандартные) построены через использование указателей на интерфейсы.

Это удобно с точки зрения полиморфизма. 
Это позволяет избавится от boxing\unboxing value types - если эти типы реализуют интерфейсы..
Это обеспечивает защищенность типа, мы имеем ссылку на интерфейс - значит можем вызывать только члены интерфейса, а их немного, их тип и кол-во постоянны и не не зависят от типа, реализующего интерфейс.

Цитата(Лена @  24.10.2007,  18:55 Найти цитируемый пост)
Сортировка в первом коде будет работать и в случае такого обявления int IComparable.CompareTo(oblect obj) и в случае если это объявление будет заменено на public int CompareTo(oblect obj).  Ошибки не будет.

ошибки не будет, т.к. метод Sort требует параметр типа IComparer. Получив параметр типа Car, CLR попытается привести его к IComparer и это получится. Но это - плохой стиль, в принципе. Что такое типозащищенность? Ты можешь передать в Sort и не Сar, а что угодно, под видом object. Компилятор ошибки не заметит. Но во время выполнения, когда этот obj будет приводиться к IComparer и окажется, что этот obj не реализует интерфейса - ты получишь run time error.

Автор: Лена 25.10.2007, 09:56
Спасибо, в общих чертах понятно: надо всегда в производном классе реализовывать интрефейсные методы через полное имя для надежности (int IComparable.CompareTo(oblect obj)).

Код автора в книге:
Код

public class Point : ICloneable
{
..........
//реализация метода интерфейса
public object Clone()
{
return new Point(this.x, this.y);
}
..........
}


Лучше так реализовывать:
Код

public class Point : ICloneable
{
..........
//реализация метода интерфейса
object ICloneable.Clone()
{
return new Point(this.x, this.y);
}
..........
}

Оба подхода правильные, только второй ограничивает доступ. Можно получить доступ только через интерфейсную ссылку.

Нет у меня глубоко понимание полезности интрефейсов после С++. Можно же было просто абстракные классы с абстакными методами делать и их наследовать и реализовывать в производных. Туман.  smile 

P.S.
Новая идея реализвать класс Car сразу двумя методами:


Код

public int CompareTo(Car car)//тут убрали object
{
if (this.carID > car.carID)
return 1;
if (this.carID < car.carID)
return -1;
else
return 0;
}

int IComparable.CompareTo(oblect obj)
  {
  Car temp = (Car)obj;
  if(this.carID > temp.carID)
  return 1;
  if(this.carID < temp.carID)
  return -1;
  else 0;
  }


 smile 

Автор: tol05 25.10.2007, 11:24
Нормальная идея. 
Когда требуется безопасный CompareTo, но с параметром object - через IComparable.CompareTo

Когда работа только с Car - через
Код

public int CompareTo(Car car)

кстати, зачем код дублировать? В IComparable.CompareTo() нужно CompareTo(Car car) вызывать (раз уж приводишь объект к Car). Если что-то изменится в алгоритме сравнения, то в двух местах менять не прийдется.

Автор: VisualProgrammerNET 26.10.2007, 12:31
К слову, какой алгоритм сортировки используется стандартным дотнетовским Sort()? 

Автор: Zapozidon 26.10.2007, 12:39
MSDN про Sort:
Цитата

This method uses Array.Sort, which uses the QuickSort algorithm.

Другие наверняка тоже.

Автор: VisualProgrammerNET 26.10.2007, 12:50
Да уж, метод Хоара особо быстрым не назовёшь... Надо будет учесть =)

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)