DupeString — Функция Delphi

DupeString — Функция Delphi

Строки в Delphi состоят из одоного (тип ShortString ) или двух байтов (тип AnsiString, WideString ), содержащих указание количества символов в строке, и последовательности символов. Таким образом ShortString максимально может содержать до 255 символов и занимать память 2 байта ..256 байт, а AnsiString или WideString — максимально могут содержать примерно 2 x 10 30 символов и занимать память 4 байта .. 2 Гбайта.

В типе AnsiString символы кодируются в коде ANSI, а в типе WideString — в коде Unicode.

Общим типом является тип String , который может соответствовать как типу ShortString , так и типу AnsiString . Это определяется директивой компилятора $H . По умолчанию используется <$H+>, и тип String равен типу AnsiString .

Кроме того имеется тип PChar , представляющий так называемую строку с завершающим нулем. Строки с завершающим нулем не содержат байтов длины. В отличие от обычных строк они состоят из последовательности ненулевых символов, за которым следует символ NULL (#0). Никаких ограничений на длину строк с завершающим нулем не накладывается. Фактически он указывает на символ

Расширенный синтаксис позволяет ставить в соответствие строкам с завершающим нулем символьный массив типа

где X — положительное число типа Integer , определяющее количество символов в строке, не считая завершающего символа с кодом 0. В отличие от типа String , символ с индексом 0 здесь является первым символом строки, а последний символ с индексом X — завершающим символом с кодом 0. (см. Функции работы со строками с завершающим нулем)

Список литературы:

  1. Гофман В.Э., Хомоненко А.Д. Delphi 6. — СПб. БХВ-Петербург, 2002. — 1152 с.: ил.
  2. Турбо Паскаль 7.0 — К. Торгово-издательское бюро BHV, 1996 — 448 с.: ил.
  3. Delphi7 Help

Класс TStrings — операции со строковыми данными в Делфи

Класс TStrings является базовым классом для операций со строковыми данными. Этот класс представляет собой контейнер для строк (коллекцию или массив строк). Для операций со строками класс TStrings предоставляет соответствующие свойства и методы. От класса TStrings происходит большое количество производных классов, например, TStringList, которые могут использоваться для задания различных типов строк.

Визуальные компоненты, способные работать со списком строк, имеют свойства, которые являются массивами строк, содержащихся в этих компонентах. Например, для списков ListBox и DBListBox и для групп зависимых переключателей RadioGroup и DBRadioGroup таким свойством является Items, а для многострочных редакторов Memo и DbMemoLines.

Указанные свойства для визуальных компонентов ListBox и Memo доступны при разработке и при выполнении приложения, а для визуальных компонентов DBListBox и DBMemo, связанных с данными, — только при выполнении приложения.

Особенности класса TStrings

Рассмотрим особенности и использование класса TStrings на примере свойства Items списков. Работа с другими объектами типа TStrings происходит аналогично.

Каждый элемент списка является строкой, к которой можно получить доступ по ее номеру в массиве строк Items. Отсчет элементов списка начинается с нуля. Для обращения к первому элементу нужно указать Items[0], ко второму— Items[1], к третьему — Items[2] и т. д. При операциях с отдельными строками программист должен контролировать номера строк в списке и не допускать обращения к несуществующему элементу. Например, если список содержит три строки, то попытка работы с десятой строкой приведет к исключению.

Свойство Count

Свойство Count типа Integer задает число элементов в списке. Поскольку первый элемент списка имеет нулевой номер, то номер последнего элемента равен Count-1.

Например, присваивание элементам списка ListBox1 новых значений может быть реализовано так:

Методы Add и Insert

Методы Add и Insert служат для добавления/вставки строк в список. Функция Add (const S: string): integer добавляет заданную параметром S строку в конец списка, а в качестве результата возвращает положение нового элемента в списке. Процедура Insert (Index: Integer; const S: String) вставляет строку S в позицию с номером, определяемым параметром index. При этом элементы списка, находившиеся до операции вставки в указанной позиции и ниже, смещаются вниз.

В приводимой далее процедуре к комбинированному списку СomboBox1 добавляется строка Нажата кнопка Button1:

Заполнение списка с помощью методов AddStrings и AddObject

Для заполнения списка можно использовать методы AddStrings и AddObject. Метод AddStrings позволяет при вызове увеличить содержимое списка более чем на один элемент.

Процедура AddStrings (strings: TStrings) добавляет в конец списка группу строк, определяемую параметром Strings. Класс TStrings позволяет хранить строки и ссылки на объектыпроизвольного типа.

Функция AddObject (const S: String; AObject: TObject): Integer добавляет в конец списка строку S и связанную с ней ссылку на объект, указываемую параметром AObject.

Рассмотрим следующий пример заполнения списка:

Здесь список TS заполняется перечнем названий страниц блокнота PageControl1 при создании формы Form1. Вместе с названиями запоминаются ссылки на страницы. Страницы блокнота имеют тип TTabSheet. Знание типа необходимо при последующей работе с задаваемыми посредством ссылок объектами, в частности, для корректного выполнения операции, такой как программное переключение страниц управляющего элемента PageControl1. Вместо переменной TS можно использовать другой список подходящего типа, например, список компонента ListBox, доступный через свойство Items.

В процессе создания приложений иногда необходимо, чтобы один список содержал те же данные, что и другой. Такое согласование списков достаточно просто выполняется с помощью методов AddStrings и Assign. Последний из методов также позволяет при вызове увеличить содержимое списка более чем на один элемент. Проверить, требуется операция согласования списков или нет, можно с помощью метода Equals.

Процедура Assign

Процедура Assign (Source: TPersistent) присваивает один объект другому, при этом объекты должны иметь совместимые типы. В результате выполнения процедуры информация копируется из одного списка в другой с заменой содержимого. Если размеры списков (число элементов) не совпадают, то после замены число элементов заменяемого списка становится равным числу элементов копируемого списка.

Функция Equals

Функция Equals (Strings: TStrings): Boolean используется для определения, содержат ли два списка строк одинаковый текст. Если содержимое списков совпадает, то функция возвращает значение True, в противном случае— значение False. Содержимое списков одинаково, если списки равны по длине и совпадают все их соответствующие элементы.

В приведенном далее примере производится согласование двух списков по содержанию:

В случае, если списки не совпадают, содержимое списка ListBox1 копируется в список ListBox2, в результате чего содержимое списков становится одинаковым.

Удаление элементов списка с помощью методов Delete и Сlear

Для удаления элементов списка используются методы Delete и Сlear. Метод Delete (index: integer) удаляет элемент с номером, заданным параметром index. При попытке удаления несуществующей строки сообщение об ошибке не выдается, но метод Delete не срабатывает.

при нажатии кнопки Button2 из комбинированного списка ComboBox1 удаляется пятая строка.

Метод Сlear очищает список, удаляя все его элементы в следующей процедуре:

при нажатии кнопки btnClearPersonalList очищается список lbPersonal.

Процедура Move

Процедура Move (Curindex, NewIndex: integer) перемещает элемент из позиции с номером CurIndex в новую позицию с номером NewIndex. Если указанный номер выходит за пределы списка, то возникает исключение.

Поиск элементов в списке процедурой IndexOf

Поиск элемента в списке можно выполнить с помощью метода IndexOf. Процедура IndexOf (const S: string): integer определяет, содержится ли строка S в списке. В случае успешного поиска процедура возвращает номер позиции найденной строки в списке; если строковый элемент не найден, то возвращается значение −1.

Работа с текстовыми файлами с помощью методов SaveToFile и LoadFromFile

У класса TStrings есть методы SaveToFile и LoadFromFile, позволяющие непосредственно работать с текстовыми файлами. Эти методы предоставляют возможность сохранения строк списка в текстовом фате на диске и последующего чтения строк из этого файла. Символы файла кодируются в системе ANSI.

Процедура SaveToFile (const FileName: String) сохраняет строковые элементы списка в файле FileName. Если заданный файл отсутствует на диске, то он создается. В последующем сохраненные строки можно извлечь из файла, используя метод LoadFromFile. Например:

Здесь содержимое списка ListBox3 записывается в файл names.txt каталога C:\COMPANY.

Процедура LoadFromFile (const FileName: String) заполняет список содержимым указанного текстового файла, при этом предыдущее содержимое списка стирается. Если заданный файл отсутствует на диске, то возникает исключение.

Пример заполнения списка содержимым файла:

Файл personal.txt содержит фамилии сотрудников организации. При запуске приложения содержимое этого файла загружается в комбинированный список ComboВох2.

При конструировании приложения изменение списка строк выполняется с помощью строкового редактора String List Editor.

Его можно вызвать из окна Инспектора объектов двойным щелчком мыши в области значения свойства типа TStrings (например, в области значения свойства Items списка ListBox).

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

Работа со строковыми типами данных в Delphi

Строковый тип данных — один из самых часто используемых в программах тип. Действительно, без него не обходится практически ни один алгоритм. Даже программы, выполняющие исключительно математические операции, порой, написаны с использованием строковых типов данных.

Строка — это последовательность символов. В Object Pascal существует несколько строковых типов. Вот основные из них:

Для большинства целей подходит тип AnsiString (иногда называется Long String ).

Стандартные функции обработки строк:

1) Функция Length(Str: String) — возвращает длину строки (количество символов). Пример:

var
Str: String; L: Integer;
< . >
Str := ‘Hello!’ ;
L := Length(Str);

2) Функция SetLength(Str: String; NewLength: Integer) позволяет изменить длину строки. Если строка содержала большее количество символов, чем задано в функции, то «лишние» символы обрезаются. Пример:

var Str: String;
< . >
Str := ‘Hello, world!’ ;
SetLength(Str, 5);

3) Функция Pos(SubStr, Str: String) — возвращает позицию подстроки в строке. Нумерация символов начинается с единицы (1). В случае отсутствия подстроки в строке возращается 0. Пример:

var Str1, Str2: String; P: Integer;
< . >
Str1 := ‘Hi! How do you do?’ ;
Str2 := ‘do’ ;
P := Pos(Str2, Str1);

4) Функция Copy(Str: String; Start, Length: Integer) — возвращает часть строки Str, начиная с символа Start длиной Length. Ограничений на Length нет — если оно превышает количество символов от Start до конца строки, то строка будет скопирована до конца. Пример:

var Str1, Str2: String;
< . >
Str1 := ‘This is a test for Copy() function.’ ;
Str2 := Copy(Str1, 11, 4);

5) Процедура Delete(Str: String; Start, Length: Integer) — удаляет из строки Str символы, начиная с позиции Start длиной Length. Пример:

var Str1: String;
< . >
Str1 := ‘Hello, world!’ ;
Delete(Str1, 6, 7);

6) Функции UpperCase(Str: String) и LowerCase(Str: String) преобразуют строку соответственно в верхний и нижний регистры:

var Str1, Str2, Str3: String;
< . >
Str1 := ‘hELLo’ ;
Str2 := UpperCase(Str1); < Str2 = "HELLO" >
Str3 := LowerCase(Str1);

Строки можно сравнивать друг с другом стандартным способом:

var Str1, Str2, Str3: String; B1, B2: Boolean;
< . >
Str1 := ‘123’ ;
Str2 := ‘456’ ;
Str3 := ‘123’ ;
B1 := (Str1 = Str2); < B1 = False >
B2 := (Str1 = Str3);

Если строки полностью идентичны, логическое выражение станет равным True.

Дополнительные функции обработки строк:

В модуле StrUtils.pas содержатся полезные функции для обработки строковых переменных. Чтобы подключить этот модуль к программе, нужно добавить его имя ( StrUtils ) в раздел Uses .

1) PosEx(SubStr, Str: String; Offset: Integer) — функция аналогична функции Pos() , но позволяет задать отступ от начала строки для поиска. Если значение Offset задано (оно не является обязательным), то поиск начинается с символа Offset в строке. Если Offset больше длины строки Str, то функция возратит 0. Также 0 возвращается, если подстрока не найдена в строке. Пример:

uses StrUtils;
< . >
var Str1, Str2: String; P1, P2: Integer;
< . >
Str1 := ‘Hello! How do you do?’ ;
Str2 := ‘do’ ;
P1 := PosEx(Str2, Str1, 1); < P1 = 12 >
P2 := PosEx(Str2, Str1, 15);

2) Функция AnsiReplaceStr(Str, FromText, ToText: String) — производит замену выражения FromText на выражение ToText в строке Str. Поиск осуществляется с учётом регистра символов. Следует учитывать, что функция НЕ изменяет самой строки Str, а только возвращает строку с произведёнными заменами. Пример:

uses StrUtils;
< . >
var Str1, Str2, Str3, Str4: String;
< . >
Str1 := ‘ABCabcAaBbCc’ ;
Str2 := ‘abc’ ;
Str3 := ‘123’ ;
Str4 := AnsiReplaceStr(Str1, Str2, Str3);

3) Функция AnsiReplaceText(Str, FromText, ToText: String) — выполняет то же самое действие, что и AnsiReplaceStr(), но с одним исключением — замена производится без учёта регистра. Пример:

uses StrUtils;
< . >
var Str1, Str2, Str3, Str4: String;
< . >
Str1 := ‘ABCabcAaBbCc’ ;
Str2 := ‘abc’ ;
Str3 := ‘123’ ;
Str4 := AnsiReplaceText(Str1, Str2, Str3);

4) Функция DupeString(Str: String; Count: Integer) — возвращает строку, образовавшуюся из строки Str её копированием Count раз. Пример:

uses StrUtils;
< . >
var Str1, Str2: String;
< . >
Str1 := ‘123’ ;
Str2 := DupeString(Str1, 5);

5) Функции ReverseString(Str: String) и AnsiReverseString(Str: AnsiString) — инвертируют строку, т.е. располагают её символы в обратном порядке. Пример:

uses StrUtils;
< . >
var Str1: String;
< . >
Str1 := ‘0123456789’ ;
Str1 := ReverseString(Str1);

6) Функция IfThen(Value: Boolean; ATrue, AFalse: String) — возвращает строку ATrue, если Value = True и строку AFalse если Value = False. Параметр AFalse является необязательным — в случае его отсутствия возвращается пустая строка.

uses StrUtils;
< . >
var Str1, Str2: String;
< . >
Str1 := IfThen(True, ‘Yes’ ); < Str1 = "Yes" >
Str2 := IfThen(False, ‘Yes’ , ‘No’ );

Мы рассмотрели функции, позволяющие выполнять со строками практически любые манипуляции. Как правило, вместо строки с указанным типом данных, можно использовать и другой тип — всё воспринимается одинаково. Но иногда требуются преобразования. Например, многие методы компонент требуют параметр типа PChar , получить который можно из обычного типа String функцией PChar(Str: String) :

uses ShellAPI;
< . >
var FileName: String;
< . >
FileName := ‘C:\WINDOWS\notepad.exe’ ;
ShellExecute(0, ‘open’ , PChar(FileName), » , » , SW_SHOWNORMAL);

Тип Char представляет собой один-единственный символ. Работать с ним можно как и со строковым типом. Для работы с символами также существует несколько функций:

Chr(Code: Byte) — возвращает символ с указанным кодом (по стандарту ASCII):

Ord(X: Ordinal) — возвращает код указанного символа, т.е. выполняет противоположное действие функции Chr() :

var X: Integer;
< . >
X := Ord( ‘F’ );

Из строки можно получить любой её символ — следует рассматривать строку как массив. Например:

var Str, S: String; P: Char;
< . >
Str := ‘Hello!’ ;
S := Str[2]; < S = "e" >
P := Str[5];

В этой статье описаны основные приёмы работы со строковыми типами данных. Как правило, этих данных достаточно для написания любого алгоритма.

Ссылки по теме

Популярные статьи
Информационная безопасность Microsoft Офисное ПО Антивирусное ПО и защита от спама Eset Software


Бестселлеры
Курсы обучения «Atlassian JIRA — система управления проектами и задачами на предприятии»
Microsoft Office 365 для Дома 32-bit/x64. 5 ПК/Mac + 5 Планшетов + 5 Телефонов. Подписка на 1 год. Электронный ключ
Microsoft Windows 10 Профессиональная 32-bit/64-bit. Все языки. Электронный ключ
Microsoft Office для Дома и Учебы 2020. Все языки. Электронный ключ
Курс «Oracle. Программирование на SQL и PL/SQL»
Курс «Основы TOGAF® 9»
Microsoft Windows Professional 10 Sngl OLP 1 License No Level Legalization GetGenuine wCOA (FQC-09481)
Microsoft Office 365 Персональный 32-bit/x64. 1 ПК/MAC + 1 Планшет + 1 Телефон. Все языки. Подписка на 1 год. Электронный ключ
Windows Server 2020 Standard
Курс «Нотация BPMN 2.0. Ее использование для моделирования бизнес-процессов и их регламентации»
Антивирус ESET NOD32 Antivirus Business Edition
Corel CorelDRAW Home & Student Suite X8

О нас
Интернет-магазин ITShop.ru предлагает широкий спектр услуг информационных технологий и ПО.

На протяжении многих лет интернет-магазин предлагает товары и услуги, ориентированные на бизнес-пользователей и специалистов по информационным технологиям.

Хорошие отзывы постоянных клиентов и высокий уровень специалистов позволяет получить наивысший результат при совместной работе.

Абстрактный класс

27.04.2020, 18:03

Создать абстрактный класс — млекопитающие
Задание : Создать абстрактный класс – млекопитающие. Определить производные классы – животные и.

Создать абстрактный класс Товар
И так сам курсачь состоит из трех заданий: ПЕРВОЕ:создать абстрактный класс Товар с методами.

Создать абстрактный базовый класс с виртуальной функцией
Добрый день! Помогите пожалуйста. Создать абстрактный базовый класс с виртуальной функцией -.

Создать абстрактный класс Figure с методами вычисления площади и периметра, а также методом, выводящим информацию
Помогите пожалуйста,вот задания: 1. Создать абстрактный класс Figure с методами вычисления площади.

Реализовать абстрактный тип данных
Реализовать абстрактный тип данных Стек в виде класса с помощью динамических массивов. Описать.

Delphi абстрактных вызовов функций с другим именем, чем базовый класс

Скажем, у меня есть функция

и я пытаюсь добавить

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

Я хочу продолжать называть GetFieldName, сделать это не абстрактным, и сделать некоторые битные типажи называть GetFieldNameA, который станет технически абстрактной версией первой GetFieldName. (Я не хочу, чтобы изменить базовый класс на всех)

Есть ли способ, как добавление «имя» ключевого слова для внешних ссылок, чтобы иметь абстрактную функцию с другим именем в подклассе?

То, что я себе в конечном итоге с что-то вроде:

Нет, вы не можете делать то, что вы предлагаете.

Вместо этого переопределения GetFieldName . Были ли это преобразовать PChar к PAnsiChar (при необходимости) перед вызовом GetFieldNameA . Последнее не должно быть (и не может, на самом деле) быть маркированы override . Это может быть обычная невиртуальном функция.

Неудачная часть этого предложения является то , что вы должны сделать это в каждом потомке класса. В качестве альтернативы можно добавить виртуальный абстрактный GetFieldNameA в базовый класс , а затем изменить все потомки , чтобы переопределить , что вместо GetFieldName . Изменение GetFieldName базового класса для вызова GetFieldNameA . Но это не стартер , если вы не можете изменить базовый класс.

Если я понял ваш вопрос правильно, вы можете обмануть Delphi впрыскивания заменить базовый класс.

Если класс, который объявляет оригинальный GetFieldName называется TClass1 объявлен в группы1 (па или DCU), то:

Блог GunSmoker-а (переводы)

. when altering one’s mind becomes as easy as programming a computer, what does it mean to be human.

среда, 13 июля 2011 г.

Виртуальные методы и inherited

Это перевод Virtual methods and inherited. Автор: Hallvard Vassbotn.

Delphi имеет необычно богатую языковую поддержку полиморфного поведения. Самая простая и базовая, которую большинство программистов ассоциируют с полиморфизмом, — это виртуальные методы.

Виртуальный метод объявляется в своём базовом классе с использованием директивы virtual : Базовый класс может иметь реализацию по умолчанию для виртуального метода, а может и не иметь. Если реализации по умолчанию нет, то вы помечаете метод как абстрактный (директива abstract ), вынуждая наследников класса создавать свою реализацию метода в обязательном порядке. Всё это — базовые вещи, которые знают все Delphi программисты. В зависимости от реализации (и документации!) базового класса, класс-наследник может решить вызывать унаследованный метод в самом начале, перед выполнением своих действий, либо в середине (довольно редко), либо после своих действий, в конце, либо же не вызывать вовсе. Существует два способа вызова унаследованного варианта метода, с тонкими отличиями: Этот код безусловно вызовет унаследованный метод Draw базового класса. Если метод в базовом классе — абстрактный, то этот вызов завершиться неудачей, возбуждая исключение EAbstractError во время выполнения (или Run-Time ошибку 210, если вы не используете исключения).

Альтернативный синтаксис вызова — просто написать inherited; , например: Этот код будет работать идентично предыдущему для случаев, когда базовый класс содержит не абстрактный метод. Этот код также автоматически создаётся средством автодополнения кода, когда вы реализуете замещение метода (override). Кроме того, он же используется IDE, при вставке обработчиков событий форм с визуальным наследованием.

Если же метод базового класса является абстрактным, либо же базовый класс вообще не содержит метода (для не виртуальных методов), то вызов inherited становится noop (No-Operation — пустым оператором). Компилятор не генерирует для него кода (и поэтому вы не можете поставить на него точку останова). Этот механизм является частью отличной версионной устойчивости языка Delphi.

Один подводный камень с синтаксисом inherited; — он не поддерживается для функций. Для функций вам нужно использовать явный синтаксис с указанием имени метода и его аргументов. К примеру: Это может выглядеть как чрезмерное ограничение дизайна языка Delphi, но я думаю, что это не случайно. Смысл этого, вероятно, в том, что если TMyClass.MethodC является абстрактным (или будет сделан абстрактным в будущем), то присваивание результата вызова в Result в классе-потомке будет удалено, что приведёт к неожиданному неопределенному значению. Это, конечно же, приведёт к скрытым багам в коде.

Однако, я думаю, что здесь есть небольшой пробел в синтаксисе унаследованного вызова. Во многих отношениях процедура, которая принимает out параметры (а в некоторых случаях и var параметры), ведёт себя как функция, возвращающая результат. Так, на мой взгляд, синтаксис inherited; должен быть запрещён при вызове методов с out (и, возможно, var ) параметрами. Сейчас это не так. Этот код означает, что если метод родительского класса является абстрактным (или просто отсутствует в случае не виртуального метода), то значение выходного параметра будет неопределённым. На мой взгляд, компилятор должен запрещать такие вызовы inherited; , требуя явного синтаксиса inherited MethodB(A); Но кота уже выпустили из мешка и уже слишком поздно что-то менять — блокировка подобных вызовов с ошибкой компиляции определённо поломает кучу кода, так что, вероятно, это тянет максимум на предупреждение (warning).

TStrings и TStringList

TStrings и TStringList

Содержание материала

Многофункциональный класс, предназначенный для хранения текстовых строк и связанных с ними объектов (любых потомков TObject). TStrings — абстрактный класс; он только описывает методы работы с наборами строк и сопутствующих им объектов, но как именно они хранятся, на его уровне не определено. Его потомки очень многочисленны; они играют основную роль в компонентах-списках (TListBox, TComboBox), редакторе (TMemo) и других. Так что вам чаще всего придется иметь дело с TStrings как со свойством одного из компонентов. В дальнейшем экземпляры этого класса и порожденных от него классов мы-будем называть наборами строк. Для создания собственных наборов строк вне компонентов предназначен потомок TStrings — TStringList, который будет рассмотрен ниже.

К строкам и объектам соответственно можно получить доступ через свойства:

property Strings[Index: Integer]: string;

property Objects[Index: Integer]: TObject;

Первое из них является векторным свойством, принимаемым по умолчанию. Общее количество пар в списке равно значению свойства:

property Count: Integer;

Класс TStrings также предназначен для хранения пар вида ‘параметр=значение’, например, в файлах инициализации (.INI). Эту возможность реализует следующее свойство:

property Values[const Name: string]: string;

При обращении к этому свойству для чтения ищется строка, содержащая подстроку (параметр) Name и символ ‘=’. Если она найдена, возвращается то, что находится в этой строке после ‘=’. Если нет, ValuesfName] равно пустой строке. При записи: если строка, содержащая параметр Name, найдена — ее значение после ‘=’ заменяется новым значением, если нет — строка добавляется. Если существующему параметру присваивается пустая строка (Valu-es[Name] := «;), то он удаляется из набора строк.

procedure BeginUpdate; procedure EndUpdate; Пара процедур, которые устанавливают и сбрасывают флаг обновления набора. Между ними, для ускорения работы, нужно заключать все операции по копированию, удалению и т. д. большого количества элементов.

procedure Clear; Осуществляет полную очистку набора.

procedure Insert(Index: Integer; const S: string); Вставляет строку S под индексом Index.

procedure Delete(Index: Integer); Удаляет строку с индексом Index.

function IndexOf(const S: string): Integer; Возвращает индекс (номер в наборе) строки S. Если она не найдена, функция возвращает -1.

function IndexOfObject(AObject: TObject): Integer; Возвращает индекс объекта в наборе. В случае неудачи возвращает -1.

function Equals(Strings: TStrings): Boolean; Сравнивает строки вызвавшего его объекта со строками объекта Strings и возвращает True в случае равенства (сравниваются число строк и все строки попарно).

function Add(const S: string): Integer — Добавляет строку S в конец набора и в случае успеха возвращает присвоенный ей индекс (он должен быть равен значению Count до добавления строки).

function AddObject(const S: string; AObject: TObject): Integer; Добавляет строку в паре с объектом. Возвращает то же, что и метод Add.

procedure Exchange(Indexl, Index2: Integer); Меняет местами пары строка+объект с индексами Indexl и Index2.

procedure Move(Curlndex, Newlndex: Integer); Перемещает пару строка+объект с позиции Curlndex в позицию Newlndex.

procedure InsertObject(Index: Integer; const S: string; AObject: TObject); Вставляет объект AObject и соответствующую ему строку S в набор под индексом Index.

Шесть методов предназначены для экспорта/импорта наборов строк :

procedure LoadFromStream(Stream: TStream);

procedure SaveToStream(Stream: TStream);

б) в файл (создавая поток и вызывая два предыдущих метода):

procedure LoadFrornFile (const FileName: strings-procedure SaveToFile(const FileName: string);

в) в данные в формате текстового редактора (подряд расположенные строки, оканчивающиеся парой символов CR/LF (16-ричные коды SOD/SOA)).

procedure AddScrings(Strings: TStrings); Добавляет в конец набора другой набор Strings.

procedure Assign(Source: TPersistent); Уничтожает прежнее содержимое набора и подставляет вместо него Source, если источник имеет тип TStrings. В противном случае возникает исключительная ситуация EConvertError.

function GetText: PChar;

выгружает строки в единый массив, где они разделены парами символов CR/LF; в конце такого массива ставится нулевой байт. Размер массива не может превышать 65520 байт; поэтому строки выгружаются до тех пор, пока их суммарная длина не превосходит этого значения.

procedure SetText(Text: PChar);

читает строки из массива Text. Строки в массиве должны быть отделены друг от друга парой символов CR/LF; допускается и один символ LF (16-ричный код $ОА). Символы с кодами 0, $lA( + ) воспринимаются как конец текста. При этом прежнее содержимое набора уничтожается.

Пишем ORM для Delphi

Всем привет!
Сегодня я расcкажу вам о своем опыте написания ORM для Delphi с использованием RTTI под влиянием практик работы с Doctrine и Java EE.

Зачем?

Под мою власть недавно попал старый проект на Delphi7 в котором ведется активная работа с базой данных под Interbase 2009. Код в этом проекте радовал, но ровно до тех пор, пока речь не заходила о самом взаимодействии с бд. Выборка данных, обновление, внесение новых записей, удаление — все это занимало немало строк в логике приложения, отчего разобраться в коде порой становилось довольно сложно (спасение в добросовестном разработчике, который круглосуточно отвечал на мои глупые вопросы). В мои руки проект был передан с целью устранения старых бед и добавления в него нового модуля, задача которого — покрыть новые таблицы БД.

Мне нравится MVC подход и очень хотелось разделить код логики с кодом модели. Да и если уж на чистоту — я не захотел для каждой новой таблицы переписывать по новой все get/set методы. Пару лет назад я познакомился с понятием ORM и мне это понравилось. Мне понравился принцип и я был в восторге, применяя его в своей работе.
В тот же момент я ринулся искать в Delphi7 хоть что-нибудь похожее на Doctrine или может генераторы Entity/Facade классов для таблиц… Ни того ни другого. Зато в поисковой выдаче нашлось несколько готовых решений. Например DORM. В целом, отличная штука и, по сути, то что нужно!

Но, не знаю бывает ли у вас, я отказался от готового решения, так как мне нужен весьма ограниченный функционал, и тащить за собой все содержимое DORM или tiOPF просто незачем. С осознанием того что хочу, с пониманием всех недостатков, я стал на этот скользкий путь и, кажется, дошел до…

Размышления

Отсутствие хоть какого-нибудь подобия на ORM — это головняк. Я вот о чем — в Java из коробки есть возможность по готовой БД создать набор классов-сущностей и фасадов для работы с созданными сущностями. Цель этих классов — предоставить разработчику готовый инструмент для взаимодействия с некоторой бд, очистить основной код логики приложения от текстов запросов и разборов результатов их выполнения. Эти же вещи используются во всех популярных PHP фреймворках, в Qt (если мне не изменяет память) в том или ином виде.

В чем же была сложность реализовать качественную библиотеку для object mapping и включить ее в состав IDE? Задача состоит в необходимости подключиться к бд, спросить у пользователя какие таблицы ему нужны в приложении, прочитать поля таблиц и связи между ними (по внешним ключам), уточнить все ли связи правильно были поняты и сгенерировать по собранным данным классы. Под генерацией я имею в виду — создание классов сущностей, задача которых — быть хранилищем одной записи из какой-то таблицы. Зная имя таблицы, можно узнать все ее поля, типы полей и по этой информации обьявить нужную информацию, сгенерировать раздел published, дописать необходимые сеттеры и геттеры… В целом задача трудоемкая, но реализуемая.
После генерации классов сущностей IDE могла бы приступить к генерации классов-фасадов (или как я их называю — Адаптеров). Адаптер представляет собой прослойку между программистом и базой данных и основная его задача — уметь получать, соответствующую некоему ключу, сущность, сохранять изменения в ней, удалять ее. В общем суть Адаптера — представить разработчику методы для работы с БД, результаты которых будут представлены в виде объектов соответствующих им сущностей.

Этот аспект разработки на Delphi мне не понравился. Опыт работы с ним у меня уже относительно большой, я вижу много плюсов в этом нелегком деле, но чем больше узнаю о новых языках и средах, ощущаю что Delphi — инструмент хотя и подходящий, но несколько не дотягивает до требуемого уровня, когда на сложную и муторную рутину мне не придется тратить столько времени.

Генерацию сущностей я готов переложить на плечи героев. Возможно кто-то даже сможет внедрить это в саму IDE как Castalia. Но я не вижу никакого смысла писать отдельно для каждой сущности методы выборки, обновления, удаления. Я не хочу. Я хочу класс, которому я передам имя сущности, у которого вызову метод findAll и получу все записи из нужной таблицы. Или напишу find(5) и получу запись с числовым ключом 5.

Процесс

Разрабатываем класс TUAdapter.
Что должен уметь делать Adapter в результате:

  1. Создает объект по имени класса
  2. Умеет получать поля класса
  3. Умеет получать значение поля обьекта по имени поля
  4. Умеет совершать выборку всех данных
  5. Умеет доставать сущность по ключу
  6. Умеет обновление данные сущности в бд
  7. Умеет удалять сущность из бд
  8. Умеет добавлять новую сущность из бд.

Мои ограничения:

  1. Нет PDO — разработка под одну БД — Interbase
  2. В Delphi7 еще старая версия RTTI. (в Rad 2010 RTTI было сильно улучшено). Можно достать только published поля
  3. Не будут реализованы связи и доставание сущностей по связям (по каким-то внутренним соображениям).

Справочник по компонентам Delphi. Часть 1
Страница 3. Класс TStrings

Класс TStrings

Многофункциональный класс, предназначенный для хранения текстовых строк и связанных с ними объектов (любых потомков TObject). TStrings — абстракт­ный класс; он только описывает методы работы с наборами строк и сопут­ствующих им объектов, но как именно они хранятся, на его уровне не опре­делено. Его потомки очень многочисленны; они играют основную роль в компонентах-списках (TListBox, TComboBox), редакторе (TMemo) и других. Так что вам чаще всего придется иметь дело с TStrings как со свойством одного из компонентов. В дальнейшем экземпляры этого класса и порожденных от него классов мы-будем называть наборами строк. Для создания собственных наборов строк вне компонентов предназначен потомок TStrings — TStringList, который будет рассмотрен ниже.

К строкам и объектам соответственно можно получить доступ через свойства:

Первое из них является векторным свойством, принимаемым по умолчанию. Общее количество пар в списке равно значению свойства:

Класс TStrings также предназначен для хранения пар вида ‘параметр=значение’, например, в файлах инициализации (.INI). Эту возможность реализует следу­ющее свойство:

При обращении к этому свойству для чтения ищется строка, содержащая подстроку (параметр) Name и символ ‘=’. Если она найдена, возвращается то, что находится в этой строке после ‘=’. Если нет, ValuesfName] равно пустой строке. При записи: если строка, содержащая параметр Name, найдена — ее значение после ‘=’ заменяется новым значением, если нет — строка добавля­ется. Если существующему параметру присваивается пустая строка (Valu-es[Name] := «;), то он удаляется из набора строк.

Методы класса приведены в таблице:

procedure BeginUpdate; procedure EndUpdate;

Пара процедур, которые устанавливают и сбрасывают флаг обновления набора. Между ними, для ускорения работы, нужно заключать все операции по копи­рованию, удалению и т. д. большого количества элементов.

Осуществляет полную очистку набора.

procedure Insert(Index: Integer; const S: string);

Вставляет строку S под индексом Index.

procedure Delete(Index: Integer);

Удаляет строку с индексом Index.

function IndexOf(const S: string): Integer;

Возвращает индекс (номер в наборе) строки S. Если она не найдена, функция возвращает -1.

function IndexOfObject(AObject: TObject): Integer;

Возвращает индекс объекта в наборе. В случае неудачи возвращает -1.

function Equals(Strings: TStrings): Boolean;

Сравнивает строки вызвавшего его объекта со строками объекта Strings и возвращает True в случае равенства (сравниваются число строк и все строки попарно).

function Add(const S: string): Integer-

Добавляет строку S в конец набора и в случае успеха возвращает присвоенный ей индекс (он должен быть равен значению Count до добавления строки).

function AddObject(const S: string; AObject: TObject): Integer;

Добавляет строку в паре с объектом. Возвращает то же, что и метод Add.

procedure Exchange(Indexl, Index2: Integer);

Меняет местами пары строка+объект с индексами Indexl и Index2.

procedure Move(Curlndex, Newlndex: Integer);

Перемещает пару строка+объект с позиции Curlndex в позицию Newlndex.

procedure InsertObject(Index: Integer; const S: string; AObject: TObject);

Вставляет объект AObject и соответствую­щую ему строку S в набор под индексом Index.

Шесть методов предназначены для экспорта/импорта наборов строк:

б) в файл (создавая поток и вызывая два предыдущих метода):

procedure LoadFrornFile (const FileName: strings-procedure SaveToFile(const FileName: string);

в) в данные в формате текстового редактора (подряд расположенные строки, оканчивающиеся парой символов CR/LF (16-ричные коды SOD/SOA)).

procedure AddScrings(Strings: TStrings! ;

Добавляет в конец набора другой набор Strings.

procedure Assign!Source: T’Persisier-t l ;

Уничтожает прежнее содержимое набора и подставляет вместо него Source, если источник имеет тип TStrings. В противном случае возникает исключительная ситуа­ция EConvertError.

выгружает строки в единый массив, где они разделены парами символов CR/LF; в конце такого массива ставится нулевой байт. Размер массива не может превышать 65520 байт; поэтому строки выгружаются до тех пор, пока их суммарная длина не превосходит этого значения.

читает строки из массива Text.Строки в массиве должны быть отделены друг от друга парой символов CR/LF; допускается и один символ LF (16-ричный код $ОА). Символы с кодами 0, $lA(+) воспринимаются как конец текста. При этом прежнее содержимое набора уничтожается.

Вызов абстрактных функций Delphi с другим именем, чем базовый класс

Скажем, у меня есть функция

и я пытаюсь добавить

который временно отключит мое подключение к базе данных для юникода.

Я хочу продолжить вызов GetFieldName, сделать его не абстрактным, и сделать некоторое приведение типов для вызова GetFieldNameA, которое станет технически абстрактной версией первого GetFieldName. (Я вообще не хочу менять базовый класс)

Есть ли способ, например добавить ключевое слово ‘name’ для внешних ссылок, иметь абстрактную функцию с другим именем в подклассе?

То, что я представляю, заканчивается тем, что:

Нет, вы не можете делать то, что вы предлагаете.

Вместо этого переопределите GetFieldName . Преобразуйте PChar в PAnsiChar (если необходимо) перед вызовом GetFieldNameA . Последнее не должно быть (и не может, фактически) быть отмечено override . Это может быть обычная не виртуальная функция.

Несчастная часть этого предложения состоит в том, что вам придется делать это в каждом классе потомков. Альтернативой является добавление виртуального абстрактного GetFieldNameA в базовый класс, а затем изменение всех потомков на переопределение, вместо GetFieldName . Измените GetFieldName в базовом классе на вызов GetFieldNameA . Но это не стартер, если вы не можете изменить базовый класс.

Если я правильно понял ваш вопрос, вы можете обмануть Delphi, введя замененный базовый класс.

Если класс, объявляющий исходное имя GetFieldName, называется TClass1, объявленным в Unit1 (pas или dcu), тогда:

Илон Маск рекомендует:  Компоненты Bootstrap
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL