![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Динамический массив структур (record) как свойство класса. [D7, XP]
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.
Тут уже никаких "пряталок" в контейнере, всё на свой страх и риск.