#delphi #record #procedure
#delphi #запись #процедура
Вопрос:
У меня есть запись, подобная этой:
Tcustomer=record
Name: string;
IDNumber: Integer;
IsMarried: boolean;
end;
И у меня есть TCustomers_Manager
класс, который хранит список всех клиентов. Возможно ли иметь процедуру, подобную этой:
Procedure ChangeCustomer(CustomerIndex: integer; field: string; value);
Это устанавливает значение для этого конкретного поля. Например:
ChangeCustomer(1, 'Name','John');
Как я могу это реализовать?
Обновление: Чтобы уточнить, мой вопрос в основном состоит из 2 частей:
1) Как я могу сопоставить имя поля (в строке) с фактическим полем в записи?
2) Возможно ли передать значение, имеющее разные типы? Или я должен передать один тип и привести его к типу (например, передать строку, а затем использовать strtoint()
)
Комментарии:
1. Да, вы можете сделать это в самых последних версиях Delphi, используя информацию о типе во время выполнения. Однако не всегда отказываться от системы статических типов — такая уж отличная идея. Вы уверены, что вам нужно это сделать?
2. Какое «конкретное поле» вы имеете в виду? Вы должны определить своих заказчиков. Вы используете IDNumber для этого? Является ли этот IDNumber уникальным? ChangeCustomer должен знать, какого клиента менять. Вам также нужен «AddCustomer». Что вы имеете в виду под «Списком клиентов»? TList или массив? Я бы использовал небольшую базу данных (возможно, в памяти) для выполнения вашей задачи.
3. @Andreas: Пожалуйста… Это всего лишь часть кода, по которой у меня возник вопрос, а не весь проект!! У меня есть TList<TCustomer> в моем классе. Я передам индекс клиента в ChangeCustomer. У меня, очевидно, есть процедура AddCustomer (). И нет, это слишком просто, чтобы использовать для этого базу данных.
Ответ №1:
Я бы использовал TClientDataSet.
- Создайте TClientDataSet с идентификатором полей, именем и т.д.
- Откройте Dataset, заполните с помощью InsertRecord или Insert/Post
- Найти запись с помощью Locate
- Используйте FieldByName(‘имя_поля’).Значение для доступа к данным или их изменения
Или вы можете взять любой компонент MemoryDataSet и использовать его таким же образом.
Второй способ — преобразовать запись в класс, объявить поля как опубликованные и использовать SetPropValue .
Если вы хотите передать какое-либо значение, вы можете использовать Variant. Но вы должны проверять типы перед назначением.
Комментарии:
1. Второй способ — это именно то, что я искал. ‘Variant’ для значения и ‘SetPropValue’ для изменения значений свойств с использованием их имен. Большое спасибо.
2. По иронии судьбы, вопрос сформулирован так, чтобы касаться RTTI с записей на диск, и то, что действительно нужно OP, — это набор данных.
Ответ №2:
Вы могли бы, например, сделать это (предполагая lst: TList<TCustomer>
, что вы сказали в комментарии):
Procedure ChangeCustomer(index: integer; i: byte; value: variant)
begin
case (i) of
0: lst[index].Name := value;
1: lst[index].IDNumber := value;
2: lst[index].IsMarried := value;
end;
end;
Вы могли бы использовать тип (или перечисление) вместо i: byte
.
Я давно не использую Delphi, поэтому воспринимайте мой пример как идею, а не как приложение Delphi!!
Комментарии:
1. Почему понижающий голос? Оставьте комментарий с объяснением, чтобы я мог понять и исправить при необходимости, пожалуйста!!!
2. Идея хорошая, но как ChangeCustomer узнает, какую запись нужно изменить? Вся концепция является неполной…
3. Это плохая идея. По двум причинам: 1) Это может сработать для записи с 3 полями, но как насчет 30 полей? Это будет беспорядок. 2) Тип значения отличается для каждого поля. Какой тип значения в определении вашей процедуры (в аргументах)?
4. @flom вам также приходится иметь дело с проблемой типа значения. Каков ваш план?
5. @Flom,
SetPropValue
работает только для классов, не для записей. Это делается с использованием RTTI. Вы можете написать свой собственный вариант, который также работает с записями, поскольку Delphi 2010 RTTI также генерируется для записей (вы упомянули, что используетеTList<>
, значит, вы на Delphi 2010 )