Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Динамический массив структур (record) как свойство класса. [D7, XP]


Страницы:   1 2 3

SingleStranger ©   (2009-02-11 13:19:00) 

Как реализовать?
Меня интересует способ с простым доступом к любому полю структуры.
Что-то типа того:
TRec = record
 field1: integer;
 field2: string;
end;

TSomeClass = class
 private
   FSRec: array of TRec;
   function GetSRec(Index: Integer): TRec;
   procedure SetSRec(Index: Integer; const Value: TRec);
 public
   function SRecAddNew: Integer;
   function SRecAdd(Value: TRec): Integer;
   property SRec[Index: Integer]: TRec read GetSRec write SetSRec;
end;

И доступ, чтобы был простым, примерно так:
var
 i: integer;
 r: TRec;
begin
 r.field1 := 1;
 r.field2 := 'aaa';
 i := SomeClass.SRecAdd(r);
 SomeClass.SRec[i].field2 := 'bbb';
end;

или как-то так:
var
 i: integer;
begin
 i := SomeClass.SRecAddNew();
 SomeClass.SRec[i].field2 := 'bbb';
end;


Ega23   (2009-02-11 18:27:00) [21]


> Вот два варианта работы со списками record


Ну нормальные варианты. Только я бы всё-таки потомка от TList написал. Дабы dispose каждый раз руками не дёргать.

Но если начать всё это дело обкладывать дурако-защитными вещами - то употеешь.
Т.к. мне никто не помешает сделать так:

SetLength(arABC,N);
for i:= 0 to N-1 do begin
  New(p);
  arABC[i] := pABC(p);
end;


А потом
New(p);
arABC[3] := p;


И аля-улю.
Т.е. мне каждый раз надо прописывать
p1 := arABC[3];
arABC[3] := p;
Dispose(p1);


Если это всё нужно один единственный раз сделать - ну можно. А если 5 раз? А 50?
А так один раз класс написал, что-то типа:


 TSerializedItem = class (TObject)
 protected
   FItemTag : Integer;
   procedure ReadStreamData(stream : TStream; bh : TBH); virtual; abstract;
   function GetItemSize : Integer; virtual; abstract;
 public
   constructor Create; virtual;

   procedure Assign(Source : TSerializedItem); virtual; abstract;
   procedure LoadFromStream(stream : TStream); overload;
   procedure LoadFromStream(stream : TStream; const DataSize : Integer); overload;
   procedure SaveToStream(stream : TStream); virtual;

 end;

 TSerializedItemClass = class of TSerializedItem;

 TSerializedItemsList = class (TObjectList)
 private
   function GetItem(Index: Integer): TSerializedItem;
   function GetItemSize : Integer;
 protected
   FItemTag : Integer;
   FSelfTag : Integer;
   FItemClass : TSerializedItemClass;
 public
   constructor Create; virtual;

   procedure Assign(Source : TSerializedItemsList);
   procedure LoadFromStream(stream : TStream); overload;
   procedure LoadFromStream(stream : TStream; const DataSize : Integer); overload;
   function AddNewItem : TSerializedItem;
   procedure SaveToStream(stream : TStream);

   property Items[Index : Integer] : TSerializedItem read GetItem; default;
   property ListSize : Integer read GetItemSize;
   property TagID : Integer read FSelfTag;
 end;

 TSerializedItemsListClass = class of TSerializedItemsList;


И гоняй его потом, как хочешь, особо не задумываясь.


Jeer   (2009-02-11 18:15:00) [22]

Тоже не вижу необходимости лишний раз в классах - просто привычка, видимо, создается.

Вот два варианта работы со списками record

type Tabc = record
   A: boolean;
   B: integer;
   C: string;
  end;

type pABC = ^Tabc;

const
    N = 10;

var
   arABC: array of pABC;
   lstABC: TList;
   p: pABC;

// Create
 lstABC := TList.Create;
 SetLength(arABC,N);
 for i:= 0 to N-1 do begin
   New(p);
   lstABC.Add(pABC(p));
   arABC[i] := pABC(p);
 end;

// Destroy
 for i:= 0 to N-1 do begin
   if  pABC(lstABC[i]) <> nil then
     dispose(pABC(lstABC[i]));
 end;
 SetLength(arABC,0);
 lstABC.Free;

// Запись через массив
 arABC[0].A := True;
 arABC[0].B := 1000;
 arABC[0].C := 'String';

// Запись через список
 p := pABC(lstABC[0]);
 p.A := True;
 p.B := 1000;
 p.C := 'String';

// Чтение
 ShowMessage(arABC[0].C);

 p := pABC(lstABC[0]);
 ShowMessage(p.C);


sniknik   (2009-02-11 17:45:00) [23]

а у то ... = ну а то ...


sniknik   (2009-02-11 17:44:00) [24]

> Ну дык, предложи свою реализацию.
предлагаю... хотя я не он.

для
> Динамический массив структур (record)
использовать рекордсет (рекордсет даже переводится как "набор рекордов"... а у то что он динамический вне всякого сомнения)

> как свойство класса.
а класс не нужен.


SingleStranger   (2009-02-11 17:26:00) [25]


> MsGuns ©   (11.02.09 16:49) [27]

Ну дык, предложи свою реализацию. И мы все подивимся, что, оказывается, можно и так!


MsGuns   (2009-02-11 16:49:00) [26]

"Фишка" реализуется простым with и опять-таки нафих классы :)


Ega23   (2009-02-11 16:42:00) [27]


> Тебе пальцем ткнуть во все эти пропертя и Get/SetValue или
> сам посмотришь на свой же "лишний" (к данном случае ессно)
> код ?


Ты вообще внимательно посмотрел на него? [12] и [13] - 2 разных подхода к организации коллекции.
В первом случае всё упрятано в private, а методы доступа, фактически, повторяют методы TObjectList. Но тут ты уже можешь закладывать проверки каких-то значений, соглашаться или не соглашаться добавлять элемент в коллекцию (по каким-то критериям), проверять диапазон индекса и возвращать не Exception а что-то другое и т.п.
Во втором случае - абсолютно тупое наследование TObjectList с переопределённым Items и GetItem, чтобы не нужно было каждый раз приводить TObject к TSomeClass

var
 i : Integer;
begin
 for i:=0 to List.Count-1 do
  if TSomeObject(List.Items[i]).Field1 = что-то then
   TSomeObject(List.Items[i]).Field2 := ещё_что-то;
end;


А если в определении property Items[...] в конце ещё директиву default добавить, то вышестоящий код будет выглядеть

var
 i : Integer;
begin
 for i:=0 to List.Count-1 do
  if List[i].Field1 = что-то then
   List[i].Field2 := ещё_что-то;
end;


Для разового обращения может быть такой код и несколько избыточен (я про классы).
Но когда это не разовое обращение - то это уже тупо время экономит.
А если такая организация хранилища ещё и общим стилем в рамках проекта является - то тут уже сам Аллах велел.


MsGuns   (2009-02-11 16:30:00) [28]

>Ega23 ©   (11.02.09 16:22) [24]
>Где ты массу ненужного кода видишь?

Тебе пальцем ткнуть во все эти пропертя и Get/SetValue или сам посмотришь на свой же "лишний" (к данном случае ессно) код ?
Так это еще пример с двумя полями, а если полей 20, да еще вложенность - я представляю, сколько сотен строчек кода займет у тебя реализация классами :)


Ega23   (2009-02-11 16:22:00) [29]


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


Где ты массу ненужного кода видишь?
И потом, для корректного доступа к этим данным, один фиг придётся тот самый "ненужный" код городить.


MsGuns   (2009-02-11 16:16:00) [30]

>Ega23 ©   (11.02.09 16:04) [22]
>Правильно! Фтопку классы! Все на асм!

Ерничать не надо. Но вот зачем там, где нужна просто организация хранения нелинейных данных (вполне умещающихся в рекорды + списки (массивы)), городить классы с горою абсолютно ненужного кода ? Ну если уж не охота морочиться с созданием-уничтожением рекордов, можно использовать коллекции..


Ega23   (2009-02-11 16:04:00) [31]


> Чтобы пожарить яичницу непременно надо завести птицефабрику
> или пихание классов куда попало во имя самих классов - отсюда
> и косяки с граблями


Правильно! Фтопку классы! Все на асм!


MsGuns   (2009-02-11 16:02:00) [32]

Чтобы пожарить яичницу непременно надо завести птицефабрику или пихание классов куда попало во имя самих классов - отсюда и косяки с граблями


Anatoly Podgoretsky   (2009-02-11 15:45:00) [33]

> SingleStranger  (11.02.2009 15:24:18)  [18]

А не надо реализовывать неверные решения, сделай класс.


Sapersky   (2009-02-11 15:36:00) [34]

Самый простой и быстрый (но наименее расширяемый и безопасный) вариант:

TRecArray = array of TRec;

TSomeClass = class
private
  FSRec: TRecArray;
public
  property SRec: TRecArray read FSRec;
end;


SingleStranger   (2009-02-11 15:24:00) [35]


> Anatoly Podgoretsky ©   (11.02.09 14:59) [17]
> А что тебя смущает

Если честно, то не понимаю реализации.


Anatoly Podgoretsky   (2009-02-11 14:59:00) [36]

> SingleStranger  (11.02.2009 14:10:11)  [11]

А что тебя смущает, у тебя же уже есть одно индексное свойство, почему бы не добавить еще два.


Ega23   (2009-02-11 14:32:00) [37]


> Хм...
> Проще некуда =)))))
> И это из структурки из двух полей =)))) Впору новый юнит
> под эту структуру выделять =))


смотри [13], там гораздо проще. Но в [12] можно сделать более безопасно. Например, с проверками диапазона Index. Чтобы он не List index out of boundsвыдавал, а что-нибудь другое.

Всё от логики зависит. Я и тот и другой методы использую, в зависимости от ситуации.


SingleStranger   (2009-02-11 14:29:00) [38]


> Ega23 ©   (11.02.09 14:20) [12]

Хм...
Проще некуда =)))))
И это из структурки из двух полей =)))) Впору новый юнит под эту структуру выделять =))

Но, всеравно спасибо. Если ничего не нарою, то воспользуюсь.


Ega23   (2009-02-11 14:28:00) [39]


> но как-то не хотелось городить класс для, вобщем-то, простой
> структуры.


Какая разница? Что класс, что рекорд. Ну перепиши вместо

TSomeRec = record
field1: integer;
field2: string;
end;

сделай

TSomeRec = class
public
field1: integer;
field2: string;
end;


Ega23   (2009-02-11 14:25:00) [40]

type

 TSomeClass = class (TObject)
 private
  FField1 : Integer;
   FField2: string;
 public
  procedure Assign(source : TSomeClass);
  property Field1 : Integer read FField1 write FField1;
  property Field2 : string read FField2 write FField2;
 end;

 TSomeClassContainer = class (TObjectList)
 private
   function GetItem(Index: Integer): TSomeClass;
 public
   property Items[Index : Integer] : TSomeClass read GetItem;
 end;
implementation

{ TSomeClass }

procedure TSomeClass.Assign(source: TSomeClass);
begin
 FField1 := source.FField1;
 FField2 := source.FField2;
end;

{ TSomeClassContainer }

function TSomeClassContainer.GetItem(Index: Integer): TSomeClass;
begin
 Result := TSomeClass(inherited GetItem(Index));
end;

end.


Тут уже никаких "пряталок" в контейнере, всё на свой страх и риск.


Страницы:   1 2 3

Наверх

Титульная страница Поиск, карта сайта Написать письмо