Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 20.03.2023, 17:28   #1
Sibedir
Тот ещё
Старожил
 
Аватар для Sibedir
 
Регистрация: 14.11.2007
Сообщений: 2,281
По умолчанию свой метод Sort для TList<MyType>

Подскажите, давно не брался за Delphi.
Я правильно понимаю, что для System.Generics.Collections.TList нельзя переопределить метод сортировки Sort не создавая наследника? Как, к примеру, это можно сделать с методом сравнения, реализовар свой экземпляр интерфейса IComparer<T>?

Делать какой-то класс-обёртку не получается. В том смысле, что у меня всё равно нет доступа к полю FList. Только свойство List, которое readonly.

Код:
  TMyArray<TMyType>.Sort(TMyArray<TMyType>.arrayofT(tmp.List));
естественно ругается
Цитата:
Constant object cannot be passed as var parameter
Или нет ни чего страшного, если я буду работать просто с элементами свойства List? Чёт мне кажется это как то тормознее же будет?

Или я вообще не туда еду?
Sibedir вне форума Ответить с цитированием
Старый 20.03.2023, 17:57   #2
Sibedir
Тот ещё
Старожил
 
Аватар для Sibedir
 
Регистрация: 14.11.2007
Сообщений: 2,281
По умолчанию

Какую-то такую аброказябру сделал.
Код:
unit MyUnit;

interface

uses
  System.Generics.Defaults, System.Generics.Collections;

type
  TMyClassForSorting<T> = class (TObject)
  private
    FComparer: IComparer<T>;
    FList: TList<T>;
    procedure MySort(L, R: Integer);
  public
    constructor Create(const AList: TList<T>; const AComparer: IComparer<T>);
    class procedure Sort(const AList: TList<T>; const AComparer: IComparer<T>); static;
  end;

implementation

{ TMyClassForSorting }

constructor TMyClassForSorting<T>.Create(const AList: TList<T>; const AComparer: IComparer<T>);
begin
  FComparer := AComparer;
  if FComparer = nil then
    FComparer := TComparer<T>.Default;
  FList := AList;
end;

class procedure TMyClassForSorting<T>.Sort(const AList: TList<T>; const AComparer: IComparer<T>);
begin
  if not Assigned(AList) or (AList.Count < 2) then Exit;
  with TMyClassForSorting<T>.Create (AList, AComparer) do begin
    MySort (0, AList.Count-1);
    Free;
  end;
end;

procedure TMyClassForSorting<T>.MySort (L, R: Integer);
begin
 // ТУТ МОЯ СОБСТВЕННАЯ СОРТИРОВКА
end;

end.
Код:
...
procedure DoSomething;
var
...
  tmp: TList<TMyType>;
...
begin
  tmp := TList<TMyType>.Create;
...
  TMyClassForSorting<TMyType>.Sort (tmp, nil);
...
end;
Вроде бы работает. Но блиииин... Это же обёртка
Sibedir вне форума Ответить с цитированием
Старый 21.03.2023, 09:07   #3
DIONISKA
Форумчанин
 
Регистрация: 07.11.2011
Сообщений: 156
По умолчанию

Если я правильно понял, то нужно что-то вроде:
Код:
uses 
	{...},System.Generics.Collections, System.Generics.Defaults;
type
//...
  TMyType = record
    field1:string;
    field2:Integer;
//...
  end;
//..
var
  Comparer: IComparer<TMyType>;
  List: TList<TMyType>;
//..
    Comparer := TDelegatedComparer<TMyType>.Create(
    function(const a0, a1: TMyType): Integer
    begin
      // тут должно быть сравнение 2-х переменных конкретного типа <T>
      //результат должен быть целочисленным 0 если-равны
      Result := a0.field2-a1.field2;
    end);
   List:= TList<TMyType>.Create(Comparer); //передаём в параметрах экземпляр IComparer
//
 List.Sort;
Или если сортировка нужна всего раз, можно не создавая отдельный экземпляр IComparer:
Код:
uses 
	{...},System.Generics.Collections, System.Generics.Defaults;
type
//...
  TMyType = record
    field1:string;
    field2:Integer;
//...
  end;
//..
var
 List: TList<TMyType>;
//..
 List:= TList<TMyType>.Create();
 List.Sort(TDelegatedComparer<TMyType>.Create(
    function(const a0, a1: TMyType): Integer
    begin
      Result := a0.field2-a1.field2;
    end));
Не понятно зачем усложнять себе жизнь :D
DIONISKA вне форума Ответить с цитированием
Старый 21.03.2023, 09:38   #4
Sibedir
Тот ещё
Старожил
 
Аватар для Sibedir
 
Регистрация: 14.11.2007
Сообщений: 2,281
По умолчанию

DIONISKA, не не, мне не Comparer нужно переопределить. Мне нужно изменить сам метод сортировки. Ну например сделать её многопоточной.

Цитата:
Не понятно зачем усложнять себе жизнь :D
Конкретно тут в целях обучения. Я решил восстановить немного скила по программированию.

Вопрос по Comparer тоже имеется, но для него я отдельную тему сейчас создаю.
Sibedir вне форума Ответить с цитированием
Старый 21.03.2023, 11:06   #5
DIONISKA
Форумчанин
 
Регистрация: 07.11.2011
Сообщений: 156
По умолчанию

А, так вопрос стоит именно в том чтобы усложнить.. Возможно стоит переопределить класс, добавив свою процедуру сортировки:
Код:
 type
 TList<T> = class(System.Generics.Collections.TList<T>)
    procedure mySort;
  end;
//..
procedure TList<T>.mySort;
begin
// тут начинаем городить пул потоков, мьютексы, многопоточную сортировку и прочее колдунство
// получить доступ к элементу:  items[i], доступа к FItems отсюда нет, и не забываем что тип <T> не определен
// сount соответственно количество, поменять местами Exchange(x,y), где x и y индексы элементов.
end;
DIONISKA вне форума Ответить с цитированием
Старый 21.03.2023, 11:27   #6
Sibedir
Тот ещё
Старожил
 
Аватар для Sibedir
 
Регистрация: 14.11.2007
Сообщений: 2,281
По умолчанию

DIONISKA,
Цитата:
переопределить метод сортировки Sort не создавая наследника?
В данном случае задача такая, как будто я не разрабатываю сами Типы и Контейнеры и не создаю их. Код их создания мне не доступен. Единственное, что мне гарантированно, что коллекции являются потомками System.Generics.Collections.TList<T >.
Например, я вполне могу управлять стилями отрисовки окон не имея отношения к их созданию и наполнению. Проект может быть уже давно разрабатывамым, но при этом мне ведь не нужно создавать новый тип и заставлять всех переделывать свой код. Мне достаточно лишь гарантии,что все окна являются потомками TForm, и через класс TForm я ими и управляю.
Sibedir вне форума Ответить с цитированием
Старый 21.03.2023, 12:49   #7
DIONISKA
Форумчанин
 
Регистрация: 07.11.2011
Сообщений: 156
По умолчанию

задача из разряда "чёрный ящик" - это не самая благодарная работа. Допустим исходные данные будут потомками System.Generics.Collections.TList<T >. В потомках многое может претерпеть изменения,включая логику хранение данных, а не только методы, потому как Потомок!=экземпляр. Допустим будет введен какой-нибудь массив хэшей, который будет использоваться для быстрого поиска, который будет перестраиваться после выполнения метода sort, add, insert или exchange. Что будет если вы попытаетесь применить к такому наследнику метод сортировки от родительского класса? А ваш собственный метод?

Цитата:
Сообщение от Sibedir Посмотреть сообщение
не создавая наследника?
Почему вас так страшат наследники классов? Недолюбливаете ООП? Если Базовый класс у них один, то его методы будут работать с обоими наследниками, даже если они переопределены. В вашем наследнике можно также переопределить метод и это всё равно будет работать.
Код:
 // допустим наш наследник
    TmyList<T> = class(System.Generics.Collections.TList<T>)
    procedure Sort(); overload
  end;
// допустим тот про который мы "не знаем" и не "создаём"
  TNOTmyList<T> = class(System.Generics.Collections.TList<T>)
    procedure dummy();
  end;
  
var
  list:TNOTmyList<string>; //экземпляр класса о котором "мы не знаем"
//..
    list:=TNOTmyList<string>.Create; 
//наполняем
    list.Add('value1');
    list.Add('value2');
    list.Add('value3');  
//сортируем
    TmyList<string>(list).Sort; //работает ведь
//....  
{ TmyList<T> }
procedure TmyList<T>.Sort;
begin
 inherited Sort; // ваш метод сортировки
   ShowMessage('sorted!');
end;
И вуаля, магия ООП в деле: всё работает и компилируется
оффтоп: А теперь на минутку представьте что тут в классе TNOTmyList переопределен метод Sort примерно как я говорил в начале, и это нигде не задокументировано, не описано и у вас на руках dcu-шка и вам либо заниматься реверс-инжинирингом либо искать того кто десять лет назад уволился и не написал документации, а тот уже сам не помнит :D
DIONISKA вне форума Ответить с цитированием
Старый 21.03.2023, 13:30   #8
Sibedir
Тот ещё
Старожил
 
Аватар для Sibedir
 
Регистрация: 14.11.2007
Сообщений: 2,281
По умолчанию

DIONISKA, ты привёл пример, где создаёшь свой наследник от TList<T>. В нём переопределяешь метод Sort. Но другие коллекции будут тоже наследниками от исходного TList<T>. Они на другой ветке наследования и твой Sort не увидят. Поэтому приходится жёстко приводить к своему типу. А вот это да, уже не хорошо.
В предложенном мной выше варианте черного ящика нет, так как с экземплярами я работаю через public свойства базового класса. Это по всем правилам ООП.
Sibedir вне форума Ответить с цитированием
Старый 21.03.2023, 14:12   #9
DIONISKA
Форумчанин
 
Регистрация: 07.11.2011
Сообщений: 156
По умолчанию

Цитата:
Сообщение от Sibedir Посмотреть сообщение
ты привёл пример, где создаёшь свой наследник от TList<T>. В нём переопределяешь метод Sort. Но другие коллекции будут тоже наследниками от исходного TList<T>.
Всё именно так
Цитата:
Сообщение от Sibedir Посмотреть сообщение
твой Sort не увидят.
Если обращаться к ним как к наследникам моего класса,то как раз увидят, никто не отменял возможность приведения классов, у меня он например приведен не явно тут:
Код:
    TmyList<string>(list).Sort;
Также можно привести к нему совершенно любой экземпляр TList<T> или его наследника, если конечно там нет совсем глобальных изменений.
Если-бы шла речь не о дженериках с их спецификой, то можно было-бы сделать всё красивее, использовать например class/record helpers, но подружить хэлперы с джерениками с их уровнем абстракции на мой взгляд если и возможно, то только с костылями. Также не работает создание dummy класса, тот самый грязный "хак"(что обычно позволяет сделать "friendly-class") для получения доступа к protected полям класса, поэтому и нет возможности получить прямой доступ к fitems и fcomparer у TList<T>.
DIONISKA вне форума Ответить с цитированием
Старый 21.03.2023, 14:27   #10
Sibedir
Тот ещё
Старожил
 
Аватар для Sibedir
 
Регистрация: 14.11.2007
Сообщений: 2,281
По умолчанию

DIONISKA, это всё я понял. Приведение типов использовать не люблю. Да и не нужно оно тут, так как работать можно через public свойства и методы просто через свой отдельный класс-дженерик от того же базового типа.
Короче, я уже смирился с обёрткой. Ща еще кое что допилю (а то пока эксперементировал, вообще всё сломал)))) и выложу сюда.
Sibedir вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Метод Sort shchelelv Microsoft Office Excel 2 07.12.2017 15:07
Метод Sort Vasya25 Microsoft Office Excel 4 21.05.2012 23:19
Создать тип даных: TYPE MyType = от 1 до 150 ArtGrek Общие вопросы Delphi 11 10.01.2012 22:50
Не работает метод SORT leonard Microsoft Office Excel 0 17.05.2011 13:18
TList->Sort ongleb Общие вопросы C/C++ 0 12.03.2010 14:58