Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2009.04.05;
Скачать: CL | DM;

Вниз

Динамический массив структур (record) как свойство класса.   Найти похожие ветки 

 
SingleStranger   (2009-02-11 13:19) [0]

Как реализовать?
Меня интересует способ с простым доступом к любому полю структуры.
Что-то типа того:
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;


 
clickmaker ©   (2009-02-11 13:39) [1]

и в чем проблема?


 
SingleStranger   (2009-02-11 13:43) [2]


> clickmaker ©   (11.02.09 13:39) [1]
> и в чем проблема?

Помоему, "Left side cannot be assigned to", если не ошибаюсь. Я код-то переписал, но нынешний вариант, вообще не устраивает. Вот и решил спросить.


 
Ega23 ©   (2009-02-11 13:44) [3]


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

function TSomeClass.GetSRec(Index: Integer): TRec;
begin
 Result := FSRec[Index];
end;

procedure TSomeClass.SetSRec(Index: Integer; const Value: TRec);
begin
 FSRec[Index].field1 := Value.field1;
 FSRec[Index].field2 := Value.field2;
end;

function TSomeClass.SRecAdd(Value: TRec): Integer;
begin
 SetLength(FSRec, Hight(FSRec) + 1);
 SetSRec(Hight(FSRec), Value);
 Result := Hight(FSRec);
end;


Что-то типа этого.
P.S. С динамическими массивами практически не работал, поэтому не уверен, как правильно отработает
procedure TSomeClass.SetSRec(Index: Integer; const Value: TRec);
begin
 FSRec[Index].field1 := Value.field1;
 FSRec[Index].field2 := Value.field2;
end;

Возможно достаточно FSRec[Index] := Value;
Надо проверять.


 
SingleStranger   (2009-02-11 13:46) [4]


> SingleStranger   (11.02.09 13:43) [2]
> Помоему, "Left side cannot be assigned to"

При доступе к полю структуры.


 
Anatoly Podgoretsky ©   (2009-02-11 13:48) [5]

> SingleStranger  (11.02.2009 13:19:00)  [0]

У тебя нет свойства SomeClass.SRec[i].field2
Или делай свойство или копируй во временную переменную.


 
Ega23 ©   (2009-02-11 13:55) [6]

Если честно, то я бы TRec сделал классом, а в TSomeClass либо TObjectList в привате организовал с методами доступа, либо сам TSomeClass от TObjectList унаследовал (это уже от логики зависит).


 
SingleStranger   (2009-02-11 13:55) [7]


> Anatoly Podgoretsky ©   (11.02.09 13:48) [5]
> > SingleStranger  (11.02.2009 13:19:00)  [0]У тебя нет свойства
> SomeClass.SRec[i].field2Или делай свойство или копируй во
> временную переменную.

Т.е.?
var
i: integer;
r: TRec;
begin
 i := 0;
 r := SomeClass.SRec[i];
 r.field2 := "bbb";
 SomeClass.SRec[i] := r;
end;

Так? Это еже неудобно.

А проще не получится?


 
SingleStranger   (2009-02-11 13:55) [8]


> Anatoly Podgoretsky ©   (11.02.09 13:48) [5]
> > SingleStranger  (11.02.2009 13:19:00)  [0]У тебя нет свойства
> SomeClass.SRec[i].field2Или делай свойство или копируй во
> временную переменную.

Т.е.?
var
i: integer;
r: TRec;
begin
 i := 0;
 r := SomeClass.SRec[i];
 r.field2 := "bbb";
 SomeClass.SRec[i] := r;
end;

Так? Это еже неудобно.

А проще не получится?


 
Anatoly Podgoretsky ©   (2009-02-11 14:00) [9]

> SingleStranger  (11.02.2009 13:55:07)  [7]

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


 
Anatoly Podgoretsky ©   (2009-02-11 14:01) [10]

> SingleStranger  (11.02.2009 13:55:08)  [8]

Проще вариант со свойствами.


 
SingleStranger   (2009-02-11 14:10) [11]


> Anatoly Podgoretsky ©   (11.02.09 14:01) [10]
> Проще вариант со свойствами.

Это как? Массив свойств?

> Anatoly Podgoretsky ©   (11.02.09 14:00) [9]
> тогда сделай функции присвоения и вызывай их.

Если это единственный способ, то видимо придется. Хотя, если честно, мне он не нравится.

> Ega23 ©   (11.02.09 13:55) [6]
> ... я бы TRec сделал классом, а в TSomeClass
> либо TObjectList в привате организовал с методами доступа ...

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

Есть еще варианты?


 
Ega23 ©   (2009-02-11 14:20) [12]


> А проще не получится?


Вот проще (сугубо ИМХО):

unit Unit2;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, Contnrs;

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 (TObject)
 private
   FItems : TObjectList;
   function GetCount: Integer;
   function GetItem(Index: Integer): TSomeClass;
   procedure SetItem(Index: Integer; const Value: TSomeClass);
 public
   constructor Create;
   destructor Destroy; override;

   function AddItem(Item : TSomeClass) : Integer;
   procedure DeleteItem(Index : Integer);
   procedure Clear;

   property Items[Index : Integer] : TSomeClass read GetItem write SetItem;
   property Count : Integer read GetCount;

 end;

implementation

{ TSomeClass }

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

{ TSomeClassContainer }

function TSomeClassContainer.AddItem(Item: TSomeClass): Integer;
begin
 Result := FItems.Add(Item);
end;

procedure TSomeClassContainer.Clear;
begin
 FItems.Clear;
end;

constructor TSomeClassContainer.Create;
begin
 FItems := TObjectList.Create(True);
end;

procedure TSomeClassContainer.DeleteItem(Index: Integer);
begin
 FItems.Delete(Index);
end;

destructor TSomeClassContainer.Destroy;
begin
 FItems.Free;
 inherited;
end;

function TSomeClassContainer.GetCount: Integer;
begin
 Result := FItems.Count;
end;

function TSomeClassContainer.GetItem(Index: Integer): TSomeClass;
begin
 try
   Result := TSomeClass(FItems.Items[i]);
 except
   Result := nil;
 end;
end;

procedure TSomeClassContainer.SetItem(Index: Integer;
 const Value: TSomeClass);
begin
 TSomeClass(FItems.Items[Index]).Assign(Value);
end;

end.


В данном варианте контейнер спрятан в private и доступ к нему идёт через public-функции.


 
Ega23 ©   (2009-02-11 14:25) [13]

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.


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


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


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


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

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

сделай

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


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


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

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

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


 
Ega23 ©   (2009-02-11 14:32) [16]


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


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

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


 
Anatoly Podgoretsky ©   (2009-02-11 14:59) [17]

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

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


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


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

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


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

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

TRecArray = array of TRec;

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


 
Anatoly Podgoretsky ©   (2009-02-11 15:45) [20]

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

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


 
MsGuns ©   (2009-02-11 16:02) [21]

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


 
Ega23 ©   (2009-02-11 16:04) [22]


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


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


 
MsGuns ©   (2009-02-11 16:16) [23]

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

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


 
Ega23 ©   (2009-02-11 16:22) [24]


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


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


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

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

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


 
Ega23 ©   (2009-02-11 16:42) [26]


> Тебе пальцем ткнуть во все эти пропертя и 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:49) [27]

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


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


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

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


 
sniknik ©   (2009-02-11 17:44) [29]

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

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

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


 
sniknik ©   (2009-02-11 17:45) [30]

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


 
Jeer ©   (2009-02-11 18:15) [31]

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

Вот два варианта работы со списками 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);


 
Ega23 ©   (2009-02-11 18:27) [32]


> Вот два варианта работы со списками 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;


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


 
Sapersky   (2009-02-11 18:41) [33]

"Фишка" реализуется простым with

Видимо так:

PRec = ^TRec;
TSomeClass = class
private
  function GetSRec(Index: Integer): PRec;
public
  property SRec[Index: Integer]: PRec read GetSRec;
end;

function TSomeClass.GetSRec(Index: Integer): PRec;
begin
Result := @FSRec[Index];
end;

...
begin
With SomeClass.SRec[i]^ do begin
 field1 := 1;
 field2 := "bbb";
end;

Хотя из дополнительных возможностей, которые дают Get/Set функции, здесь можно реализовать только контроль индексов.

Jeer ©   (11.02.09 18:15) [31]

Слава рЕкордам! Сотрём все классы! :)
http://sapersky.narod.ru/files/Arrays.rar
(Arr_AddItem, Arr_DelItem)


 
Jeer ©   (2009-02-11 18:41) [34]


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


Да понятно это все - но если плохо понимаешь, что делаешь - известна рекомендация "Займись тем, что у тебя получается"


 
Jeer ©   (2009-02-11 18:46) [35]

Да я вообще могу вас отправить в Delphi Fundamentals
Там, пожалуй, все дельфинячьи "радости" сосредоточены. :)
В том числе и такого типа.

http://fundementals.sourceforge.net


 
Джо ©   (2009-02-11 18:50) [36]


> http://fundementals.sourceforge.net

We"re Sorry but this Project hasn"t yet uploaded their personal webpage yet.
:)


 
Ega23 ©   (2009-02-11 18:54) [37]


> Да понятно это все - но если плохо понимаешь, что делаешь
> - известна рекомендация "Займись тем, что у тебя получается"


Возможно у меня это просто на автомате уже получается. Ну не люблю я рекорды. Я ещё могу понять record в случае записи в файл типизированный или там при передаче по сети какой-нибудь. Но в данном конкретном случае (как у автора) я класс бы не задумываясь написал. Тем более, что если понадобится - всегда можно геттеры и сеттеры прикрутить. Лёгким движением руки.


 
Jeer ©   (2009-02-11 20:17) [38]


> Джо ©   (11.02.09 18:50) [36]
We"re Sorry but this Project hasn"t yet uploaded their personal webpage yet.
:)


Да не проблема:
http://sourceforge.net/projects/fundementals/

Давно слежу за развитием проекта David J Butler, еще со времен динозавров.
Не ошибусь, если скажу, что с первыми релизами я ознакомился еще в прошлом веке.
Пользуюсь, не всегда, но пользуюсь.

Отличная подборка классов и утилит по структурам данных, математике, потокам, системным/интернет/xml и прочее.

Просто рекомендую всем, кто не знаком с данной библиотекой - хотя бы для "изучительных" целей.

Того оно стоит.


 
SingleStranger   (2009-02-11 20:32) [39]

Давайте я попробую приближенно описАть задачу. Может быть предложите другое решение.

Например есть класс-поток, который постоянно (ПОСТОЯННО) рисует человека. Есть структура описывающая одежду человека;
TRec = record
 DressCode: integer; // штаны, например. рубашка, шляпа, и т.п.
 Color1: TColor;
 Color2: TColor;
 Color3: TColor;
 Style: integer;
end;


Ну, можно еще десяток полей придумать, не важно.
Так вот, у класса рисующего человека есть (должен быть, по задумке) динам. массив этих TRec"ов и на основании него он прорисовывает, перебирая весь массив, одежду. Но массив может быть и пуст, а может быть наполнен 10-20 предметами.
Но при этом, ВСЕГДА есть трусы =) описанные ТОЙ ЖЕ структурой и реализованные как свойств класса, через указатель (примерно так, как предлагал MsGuns (Стволы от Майкрософт, что ли? ;) ) и Sapersky [33]), т.е. они есть всегда. И в общем-то преход к другой структуре возможен, но... Надо будет просто переписать некоторые другие вещи, непосредственно к сабжу не относящиеся.
Вот отсюда и сабж. Как реализовать набор одежды, описанной структурой TRec.

P.S. Не стоит придираться к деталям, это приближенное описание.


 
Jeer ©   (2009-02-11 20:39) [40]

P.S.
Кста - под НГ вышел, оказывается, новый релиз v 4.
Батлер опять слил все в единый каталог - пральна.

Посмотрел.. по ср. с v.3* - хорошо переработано.

Однако исчезла математике ( вроде как )

Ну и ладно - не ему спорить с современными алгоритмами - у него всегда была простая, не особо эффективная, но работающая реализация:
- векторы, матрицы, компл. числа, рац.числа, статистика, 3D преобразования и пр.

Хотя жаль - довесок неслабый был.

Впрочем, по ссылке, доступны старые версии 3.* - там это должно быть.



Страницы: 1 2 вся ветка

Текущий архив: 2009.04.05;
Скачать: CL | DM;

Наверх




Память: 0.6 MB
Время: 0.014 c
1-1209133936
Kolan
2008-04-25 18:32
2009.04.05
В MDI приложение WindowState := wsMaximized; происходит долго&amp;#133


2-1234501240
dark_volk
2009-02-13 08:00
2009.04.05
Копирование таблиц


10-1153589543
Andrey Kad.
2006-07-22 21:32
2009.04.05
Границы ячейки в Excel


2-1234454001
SultanOFF
2009-02-12 18:53
2009.04.05
Считывание с реестра акробатически избегая ошибки возможно???


3-1217909603
Viod
2008-08-05 08:13
2009.04.05
Обработка исключений ADOConnection