Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Для новичков > динмические типы


Автор: stalkerok 11.12.2008, 11:11
Добрый день! как в Delphi передать тип данных в процедуре, например:
есть несколько типов
Код

Type
DotRec = record
 id:integer;
 x:integer;
 y:integer;
 z:integer;
end;

Type
LinkRec = record
 id:integer;
 first:integer;
 last:integer;
end;

Type
NameGridRec = record
 ncell: String[255];
end;

Как в процедуре передать тип?
Код

procedure Load(передать тип);
var
  fileTP: file of ТИП;
  arrTP: ТИП;
begin
................
................
end;

Автор: MetalFan 11.12.2008, 13:19
вижу несколько вариантов:
1. Простой - Написать 3 перегруженных процедуры, каждая из которых работает со своим типом.
2. Более сложный - усложнить структуру. ввести поле "тип данных" и поле-указатель на сами данные, а в процедуре уже разбираться, что пришло.
3. Отказаться от записей и процедур и перейти на ООП.

Автор: bems 11.12.2008, 13:34
4. Перейти на D2009 и использовать дженерики

Автор: MetalFan 11.12.2008, 13:42
Цитата(bems @  11.12.2008,  13:34 Найти цитируемый пост)
. Перейти на D2009 и использовать дженерики 

а с дженериками как бы решение выглядело? я просто еще "не перешел" и "не использовал" )))

Автор: stalkerok 11.12.2008, 14:19
bems я на 2009, да действительно как бы это выглядело?

Автор: bems 11.12.2008, 15:28
ну это зависит от того, что именно нужно )))
например что-то такое
Код

procedure Load<T:record>;
var size:integer;
begin
size:=SizeOf(T);
GetMem(SomeGlobalPointerToLoadedData,size);
SomeGlobalStreamObject.Read(SomeGlobalPointerToLoadedData^,size);
end;

Глобальные переменные тут только потому что у топикстартера это процедура с одним параметром (типом). А вообще можно и что-то такое
Код

procedure Load<T:record>(SomeArg:integer;ArgOfParameterizedType:T;var AnotherArg);


ну и ниже в коде как-то так:
Код

Load<TActualType>(1,VarOfTActualType,someVar)

Автор: stalkerok 12.12.2008, 00:45
разбирался... так и не получается... я хочу написать процедуру сохранения масивов в файл с разными типами

типы
Код

Type
DotRec = record
 id:integer;
 x:integer;
 y:integer;
 z:integer;
end;
Type
LinkRec = record
 id:integer;
 first:integer;
 last:integer;
end;
Type
NameGridRec = record
 ncell: String[255];
end;


а вот процедура
Код

procedure SaveArr(FileName: String; Array???:???; typearray:?????);
var
  arrFile: file of typearray????;
  i: integer;
begin
 AssignFile(arrFile, FileName);
 ReWrite(arrFile);
 for i := Low(Array???) to High(Array???) do
  begin
    Write(arrFile, Array???[i]);
  end;
  CloseFile(arrFile);
end;


и затем просто вызывать её
Код

var
  DotArr: array of DotRec;
  LinkArr: array of LinkRec;
  GridNameArr: array of NameGridRec;
.......
procedure SaveArr('txt1', DotArr, DotRec);
procedure SaveArr('txt2', LinkArr, LinkRec);
procedure SaveArr('txt3', GridNameArr, NameGridRec);

Автор: stalkerok 12.12.2008, 12:55
Может поможет кто.  smile 

Автор: elvis79 12.12.2008, 15:19
Array -- это массив записей (array of DotRec, array of LinkRec, array of NameGridRec)

Если я правильно понял, то я б организовал через TObjectList. 
А также создал предка с виртуальными методами и от него породил бы DotRec, LinkRec и NameGridRec. Реализация методов была в каждом предке своя

Код

type
  TFigure = class
  private
  public
    procedure Save; virtual; abstruct;
  end;
  
  TDotRec = class(TFigure)
  private
  public
    procedure Save; 
  end;

  TLinkRec = class(TFigure)
  private
  public
    procedure Save; 
  end;

  
  TMyList = class(TObjectList) // --- список (вместо массива)
  private
  public
    procedure SaveToFile(const AFileName: String); 
    property Items[Index: Integer]: TFigure read GetItems write SetItems;
  end;


Реализация

Код

procedure TMyListSaveToFile(const AFileName: String); 
var
  i: Integer;
begin
  for i := 0 to Count - 1 do
    Items[i].Save;
end;

procedure TDotRec.Save; 
begin
  ShowMessage('I am DotRec');
end;

procedure TLinkRec.Save; 
begin
  ShowMessage('I am LinkRec');
end;


если заинтересует пиши, помогу

Автор: stalkerok 14.12.2008, 20:57
elvis79 Спасибо!

Насколько я понял всё равно придётся писать для каждого типа данных свою процедуру и эти процедуры будут одинаковые(в моём случае с сохранением массива в файл) а отличаться будут в процедурах только тип используемых переменных, а если типов данных 10 то писать 10 одинаковых процедур?
Но если использовать дженерики, там только написать одну процедуру, при вызове которой передавать тип данных?

заранее Спасибо!

Автор: NewDima 15.12.2008, 08:03
ну и сумбур
Код

type
MyType1 = record x, y, z: integer; end;
MyType2 = record x, y, z: single; end;
var
 Ar1: MyType1; Ar2: MyType2;
procedure SaveArrToFile(filename: TFileName; arr: pointer; len: integer);
var  i: integer; arrFile: file of byte;
begin
 AssignFile(arrFile, FileName);
 ReWrite(arrFile);
 for i:=0 to len-1 do Write(arrFile, PByteArray(arr)^[i]);
 CloseFile(arrFile);
end;


звать так:
Код

var s: string;
s1: array[1..255] of MyType1;
s2: array[1..255] of MyType2;
i: integer;
begin
s:= 'some string';
for i:=1 to 255 do s1[i].x := 1;
for i:=1 to 255 do s2[i].x := 1.1; 
SaveArrToFile('text string.txt', @s[1], length(s));
SaveArrToFile('int vector.txt',  @s1, 255*sizeof(MyType1));
SaveArrToFile('signle vector.txt',  @s2, 255*sizeof(MyType2));
  { TODO -oUser -cConsole Main : Insert code here }
end.


такой процедуре корми что захочешь, Но мой тебе совет, не используй эти функции:
Код

AssignFile
ReWrite
Write
CloseFile

большие структуры будут долго писаться (пишутся то по байтам), используй CreateFile, WriteFile

Код

function SaveArrToFile(filename: TFileName; arr: pointer; len: integer):boolean;
var  i: integer; arrFile: hfile; wr: Cardinal;
begin
Result:=false;
arrfile := CreateFile(PChar(FileName),
           GENERIC_WRITE,
           FILE_SHARE_READ,
           nil,
           CREATE_ALWAYS,
           FILE_ATTRIBUTE_NORMAL,
           0);
if (arrFile=INVALID_HANDLE_VALUE) then exit;
WriteFile(arrFile, PByteArray(arr)^, len, wr, nil);
FileClose(arrFile);
if (len<>wr) then exit;
Result:=true;
end;

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

Автор: MetalFan 15.12.2008, 11:41
Цитата(NewDima @  15.12.2008,  08:03 Найти цитируемый пост)
Но мой тебе совет, не используй эти функции:

почему? обоснуй!

Автор: NewDima 15.12.2008, 16:11
я дальше код привел, еще раз вставить?=)
найди пять различий smile 

а вообще, гибкость и расширенные возможности

Автор: MetalFan 16.12.2008, 13:39
NewDima, не вижу преимущества в приведенном коде. кто виноват, что ты объявил типизированный файл в первом варианте?

Автор: NewDima 16.12.2008, 15:41
с типизацией файла начал топикстартер.
Код

procedure SaveArrToFile(filename: TFileName; arr: pointer; len: integer);
var  i: integer; arrFile: file;
begin
 AssignFile(arrFile, FileName);
 ReWrite(arrFile, len);
 BlockWrite(arrFile, PByteArray(arr)^[0], 1);
 CloseFile(arrFile);
end;

рады? Я сторонник WinAPI и его гибкости;

Автор: stalkerok 16.12.2008, 20:40
NewDima СПАСИБО!!! то что надо! а как же читать из такого файла?  может Поможете дописать эту функцию? и для чего нужен Randomize;?

Автор: stalkerok 17.12.2008, 01:38
Пробовал так:
Код

//******************************************************************************
//Сохранение
procedure SaveArrToFile(filename: TFileName; arr: pointer; len: integer);
var
  arrFile: file;
begin
  if FileExists(filename) then
    ShowMessage('Файл существует')
  else
  begin
    AssignFile(arrFile, FileName);
    ReWrite(arrFile, len);
    BlockWrite(arrFile, PByteArray(arr)^[0], 1);
    CloseFile(arrFile);
  end;
end;

//******************************************************************************
//Загрузка
procedure LoadFileToArr(filename: TFileName; arr: pointer; len: integer);
var
  arrFile: file;
begin
  if FileExists(filename) then
  begin
    AssignFile(arrFile, FileName);
    Reset(arrFile, len);
    BlockRead(arrFile, PByteArray(arr)^[0], 1);
    CloseFile(arrFile);
  end
  else
    ShowMessage('Файла не существует');
end;


но не получается...

Автор: NewDima 17.12.2008, 07:42
лови

Добавлено через 5 минут и 32 секунды
Код

function LoadArrFromFile(filename: TFileName; arr: pointer; len: integer):boolean;
var  arrFile: file;
begin
 AssignFile(arrFile, FileName);
 Reset(arrFile, len);
 BlockRead(arrFile, PByteArray(arr)^[0], 1);
 CloseFile(arrFile);
end;

Автор: stalkerok 17.12.2008, 11:22
NewDima Спасибо! только не пойму почему то не правильно работает.
например сохранил массив длиной 4, а затем при загрузке этого массива его длина = 3876... причем файл всего 4 байта...
Код

Type
DotRec = record
  id:integer;
  x:integer;
  y:integer;
  z:integer;
end;

var
  DotArr: array of DotRec;

//******************************************************************************
//Сохранение
procedure SaveArrToFile(filename: TFileName; arr: pointer; len: integer);
var
  arrFile: file;
begin
  AssignFile(arrFile, FileName);
  ReWrite(arrFile, len);
  BlockWrite(arrFile, PByteArray(arr)^[0], 1);
  CloseFile(arrFile);
end;

//******************************************************************************
//Загрузка
procedure LoadArrFromFile(filename: TFileName; arr: pointer; len: integer);
var
  arrFile: file;
begin
  AssignFile(arrFile, FileName);
  Reset(arrFile, len);
  BlockRead(arrFile, PByteArray(arr)^[0], 1);
  CloseFile(arrFile);
end;


вызываю
Код

LoadArrFromFile('test.txt', @DotArr, len);
SaveArrToFile('test.txt', @DotArr, len);


а если сохранять массив из типа:
Код

Type
NameGridRec = record
  ncell: String[255];
end;

вообще вылетает с ошибкой...

Автор: MetalFan 17.12.2008, 11:43
читай про статические и динамические массивы.
в твоем случае тебе надо передать указатель не на переменную-массив, а на первый элемент массива в эти функции
так же неплохо сохранить длину массива, например, в начале файла.

Автор: stalkerok 17.12.2008, 12:42
MetalFan не понял это как подскажите пожалуйста.

Автор: NewDima 17.12.2008, 15:32
не
Код

LoadArrFromFile('test.txt', @DotArr, len);
SaveArrToFile('test.txt', @DotArr, len);
, а
Код

LoadArrFromFile('test.txt', @DotArr[1], len);
SaveArrToFile('test.txt', @DotArr[1], len);


Добавлено @ 15:39
да, как сказал MetalFan, читай теорию  smile 
и в следующий раз, если хочешь чему-то научиться, то  лучше спрашивай не "как?", а "вот так правильно?" и приводи свои додумки, а мы объясним, что правильно и не правильно и почему. Иначе все, что тебе здесь говорят ты забудешь через неделю

Автор: stalkerok 17.12.2008, 16:05
Спасибо Вам, но так и не получается, хотя сделал всё как Вы подсказали:
Код

//******************************************************************************
//Сохранение
procedure SaveArrToFile(filename: TFileName; arr: pointer; len: integer);
var
  arrFile: file;
begin
  AssignFile(arrFile, FileName);
  ReWrite(arrFile, len);
  BlockWrite(arrFile, PByteArray(arr)^[0], 1);
  CloseFile(arrFile);
end;
//******************************************************************************
//Загрузка
procedure LoadArrFromFile(filename: TFileName; arr: pointer; len: integer);
var
  arrFile: file;
begin
  AssignFile(arrFile, FileName);
  Reset(arrFile, len);
  BlockRead(arrFile, PByteArray(arr)^[0], 1);
  CloseFile(arrFile);
end;


использование
Код

Type
DotRec = record
  id:integer;
  x:integer;
  y:integer;
  z:integer;
end;

var
  DotArr: array of DotRec;

  SaveArrToFile('test.txt', @DotArr[1], 4);
  DotArr:= nil;
  SetLength(DotArr, 4);
  LoadArrFromFile('test.txt', @DotArr[1], 4);


но, например при сохранении:
Код

DotArr[0].id:=0
DotArr[0].x:=3
DotArr[0].y:=3
DotArr[0].z:=0
DotArr[1].id:=1
DotArr[1].x:=3
DotArr[1].y:=6
DotArr[1].z:=3
DotArr[2].id:=2
DotArr[2].x:=5
DotArr[2].y:=3
DotArr[2].z:=6
DotArr[3].id:=3
DotArr[3].x:=4
DotArr[3].y:=7
DotArr[3].z:=8


загружается
Код

DotArr[0].id:=0
DotArr[0].x:=0
DotArr[0].y:=0
DotArr[0].z:=0
DotArr[1].id:=1
DotArr[1].x:=0
DotArr[1].y:=0
DotArr[1].z:=0
DotArr[2].id:=0
DotArr[2].x:=0
DotArr[2].y:=0
DotArr[2].z:=0
DotArr[3].id:=0
DotArr[3].x:=0
DotArr[3].y:=0
DotArr[3].z:=0


Возможно файл сохраняется не полностью? ведь например вышеприведённый файл занимает 4байта, не мало?

Автор: NewDima 17.12.2008, 16:48
Код

type
dot = record
id, x, y, z: integer;
end;
var ArrDot: array[1..3] of dot;
    ArrDot1: array[1..3] of dot;
//******************************************************************************
//Ñîõðàíåíèå
procedure SaveArrToFile(filename: TFileName; arr: pointer; len: integer);
var
  arrFile: file;
begin
  AssignFile(arrFile, FileName);
  ReWrite(arrFile, len);
  BlockWrite(arrFile, PByteArray(arr)^[0], 1);
  CloseFile(arrFile);
end;
//******************************************************************************
//Çàãðóçêà
procedure LoadArrFromFile(filename: TFileName; arr: pointer; len: integer);
var
  arrFile: file;
begin
  AssignFile(arrFile, FileName);
  Reset(arrFile, len);
  BlockRead(arrFile, PByteArray(arr)^[0], 1);
  CloseFile(arrFile);
end;
var i: integer;
fr: string;
begin
randomize();
for i:=1 to 3 do
 begin
  ArrDot[i].id := i;
  ArrDot[i].x := RandomRange(0, 2);
  ArrDot[i].y := RandomRange(3, 5);
  ArrDot[i].z := RandomRange(6, 8);
  writeln(Format('ArrDot[%d].id = %d', [i, ArrDot[i].id]));
  writeln(format('ArrDot[%d].x = %d', [i, ArrDot[i].x]));
  writeln(format('ArrDot[%d].y = %d', [i, ArrDot[i].y]));
  writeln(format('ArrDot[%d].z = %d', [i, ArrDot[i].z]));
 end;
writeln('-------------------------------------');
SaveArrToFile('file.bin', @ArrDot[1], sizeof(dot)*3);
LoadArrFromFile('file.bin', @ArrDot1[1], sizeof(dot)*3);
for i:=1 to 3 do
 begin
  writeln(Format('ArrDot1[%d].id = %d', [i, ArrDot1[i].id]));
  writeln(format('ArrDot1[%d].x = %d', [i, ArrDot1[i].x]));
  writeln(format('ArrDot1[%d].y = %d', [i, ArrDot1[i].y]));
  writeln(format('ArrDot1[%d].z = %d', [i, ArrDot1[i].z]));
 end;
readln;
end.

кидай свой код в аттаче, посмотрю, скажу, что неправильно

Добавлено через 8 минут и 4 секунды
ой -йой сразу твой код не глянул.
Я тебе так скажу: учи основы! и заодно узнай, сколько байт в целом числе, потом поймешь, сколько весит твоя структура, а потом умножишь на размер массива и поймешь, сколько он на самом деле места занимает. Нет слов, одни эмоции
никому вот это не показывай:
Код

  SaveArrToFile('test.txt', @DotArr[1], 4);
  DotArr:= nil;
  SetLength(DotArr, 4);
  LoadArrFromFile('test.txt', @DotArr[1], 4);

Автор: stalkerok 17.12.2008, 17:27
NewDima СПАСИБО!

Автор: NewDima 17.12.2008, 17:37
пометь тему решеной, так принято

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