Help!!! Open Array parameters
13 отговора
367 прегледа
Help!!! Open Array parameters
type
TMyRec=record
x:integer;
y:integer;
end;
...
procedure Proc(const Params:Array of TMyRec);
Как да подавам параметри на Proc?
Само не ми казвайте, че единствения начин е:
procedure OtherProc;
var
P:Array of TMyRec;
begin
SetLength(P,10);
P[0].x:=10;
P[0].y:=15;
P[1].x:=34;
P[1].y:=25;
...
P[9].x:=43;
P[9].y:=12;
Proc(p);
end;
TMyRec=record
x:integer;
y:integer;
end;
...
procedure Proc(const Params:Array of TMyRec);
Как да подавам параметри на Proc?
Само не ми казвайте, че единствения начин е:
procedure OtherProc;
var
P:Array of TMyRec;
begin
SetLength(P,10);
P[0].x:=10;
P[0].y:=15;
P[1].x:=34;
P[1].y:=25;
...
P[9].x:=43;
P[9].y:=12;
Proc(p);
end;
Re: Help!!! Open Array parameters
Можеш да подадеш масив като заградиш елементите в квадратни скоби:
SomeProcedureWithOneParameter([1, 2, 3]);
Ако това не ти е удобно значи вероятно е по-добре да си промениш дизайна и да подаваш параметрите използвайки списък например или по някакъв друг начин, който да пасва по-добре.
SomeProcedureWithOneParameter([1, 2, 3]);
Ако това не ти е удобно значи вероятно е по-добре да си промениш дизайна и да подаваш параметрите използвайки списък например или по някакъв друг начин, който да пасва по-добре.
Re: Help!!! Open Array parameters
Ако правилно съм разбрал твоята болка - ти не искаш
всеки път да инициализираш масив само за да подадеш
параметри на процедурата, а искаш директно да си ги описваш
в параметрите при повикването. Ако съм познал - то предлагам
един такъв вариант:
Направи си една функцийка:
и викай твоята процедура така:
Така ще ти свърши ли работа?
всеки път да инициализираш масив само за да подадеш
параметри на процедурата, а искаш директно да си ги описваш
в параметрите при повикването. Ако съм познал - то предлагам
един такъв вариант:
Направи си една функцийка:
function f(x,y:integer):TMyRec;
begin
Result.x:=x;
Result.y:=y;
end;
и викай твоята процедура така:
Proc([f(1,2),f(3,4),f(5,6)]);
Така ще ти свърши ли работа?
Re: Help!!! Open Array parameters
Да. Перфектна идея!
П.С.
Т.е. да разбирам, че няма начин (синтакс) който да позвлява директно инициализиране на структури в делфи? нещо като:
Proc([(x:1;y:3),(x:2;y:8),(x:23;y:18)...(x:n;y:m)]);
П.С.
Т.е. да разбирам, че няма начин (синтакс) който да позвлява директно инициализиране на структури в делфи? нещо като:
Proc([(x:1;y:3),(x:2;y:8),(x:23;y:18)...(x:n;y:m)]);
Re: Help!!! Open Array parameters
Ти за указатели чувал ли си....
Ако правиш само четене в процедурата предавай данните по адрес.. а не си хаби памметта...
Ако правиш само четене в процедурата предавай данните по адрес.. а не си хаби памметта...
Re: Help!!! Open Array parameters
:)
Не, точно за това което ти искаш - няма.
(има само като обявяваш константа от тип record,
но там не е присвояване, а друго и там "присвояването"
става при компилацията)
А в делфи няма как да използваш оператора за присвояване
":=" за зададеш всички полета на record-а наведнъж.
Няма MyRec:=((x:1),(y:1)) или нещо подобно - което ти
всъщност искаш :)
Пък и в краен случай като писане моето предложение е
по-късо от Proc([(x:1;y:3),(x:2;y:8),(x:23;y:18)...(x:n;y:m)])
ако го имаше :)
>>> ...структури в делфи...
от Ц-то ли идваш
в нашето село им казваме "записи"
Пък и разработчиците на делфи ползват същия начин,
не съм го измислил аз :)
Виж например:
function Point(AX, AY: Integer): TPoint;
и example към нея:
познато? :)
-----
към EFEX
>>>...не си хаби памметта...
хм... не си прав.
първо човека иска друго - по-удобен синтаксис, а не става дума
за паметта. И второ паметта не се хаби защото:
"Open array constructors can be passed only as value or const parameters."
или както казваш: "Ти за указатели чувал ли си.... "
:)
Не, точно за това което ти искаш - няма.
(има само като обявяваш константа от тип record,
но там не е присвояване, а друго и там "присвояването"
става при компилацията)
А в делфи няма как да използваш оператора за присвояване
":=" за зададеш всички полета на record-а наведнъж.
Няма MyRec:=((x:1),(y:1)) или нещо подобно - което ти
всъщност искаш :)
Пък и в краен случай като писане моето предложение е
по-късо от Proc([(x:1;y:3),(x:2;y:8),(x:23;y:18)...(x:n;y:m)])
ако го имаше :)
>>> ...структури в делфи...
от Ц-то ли идваш
в нашето село им казваме "записи"
Пък и разработчиците на делфи ползват същия начин,
не съм го измислил аз :)
Виж например:
function Point(AX, AY: Integer): TPoint;
и example към нея:
This example draws a polygon in the specified shape, and fills it with the color teal.
procedure TForm1.FormActivate(Sender: TObject);
begin
Canvas.Brush.Color := clTeal;
Canvas.Polygon([Point(10, 10), Point(30, 10),
Point(130, 30), Point(240, 120)]);
end;
познато? :)
-----
към EFEX
>>>...не си хаби памметта...
хм... не си прав.
първо човека иска друго - по-удобен синтаксис, а не става дума
за паметта. И второ паметта не се хаби защото:
"Open array constructors can be passed only as value or const parameters."
или както казваш: "Ти за указатели чувал ли си.... "
:)
Re: Help!!! Open Array parameters
Нещо май не ти е ясен въпроса... а и не четеш внимателно. В първия пост прототипа на процедурата ми е:
procedure Proc(const Params:array of TMyRec);
Това значи че на Proc се подават точно 2 неща. Указател към масива и размера на масива независимо къде е инициализиран, как е създаден и колко е голям. При fastcall указателя се подава в EAX a размера в EDX, ако Proc e метод на обект указателя се подава в EDX а размера в ECX, EAX = self и т.н. Изобщо всички димамични масиви "вкл. long strings" в делфи се подават по адрес. Така че приателю вземи прочети малко как точно се подават параметрите в делфи и какво е "open array constructor" и как действа а, недей да говориш за неща който не разбираш. И понеже виждам че не четеш, да ти поясня: въпроса ми беше за "синтаксис" а не какво е указател.
procedure Proc(const Params:array of TMyRec);
Това значи че на Proc се подават точно 2 неща. Указател към масива и размера на масива независимо къде е инициализиран, как е създаден и колко е голям. При fastcall указателя се подава в EAX a размера в EDX, ако Proc e метод на обект указателя се подава в EDX а размера в ECX, EAX = self и т.н. Изобщо всички димамични масиви "вкл. long strings" в делфи се подават по адрес. Така че приателю вземи прочети малко как точно се подават параметрите в делфи и какво е "open array constructor" и как действа а, недей да говориш за неща който не разбираш. И понеже виждам че не четеш, да ти поясня: въпроса ми беше за "синтаксис" а не какво е указател.
Re: Help!!! Open Array parameters
Благодаря за изчерпателния отговор :))
Да, това което предлагаш ме устройва напълно, дето се вика нещо като макрос се получава:))
А колкото за Ц-то - да от там съм свикнал да им викам структури:))
И понеже виждам че ме разбираш (и разбираш) да те питам още нещо ако може:)
Имам следния сценарий:
Имам един клас който съм наследил от TDataSet и той взима данни от друг(и) TDataSet (в случая от TIBDataSet)
класа Х наследява TDataSet за да мога лесно да го вържа към разни DB aware контроли (гридове и т.н). Докато го преписвах (наследявах) осъзнах че в новия клас дублирам паметта за записите (буферите) т.е. заделям още един път излишно буфери които пълня от друг датасет който също е заделил буфер за същия запис. Т.е. ненужно разхищение на памет. Въпроса ми е мога ли да ползвам някак директно буферите от source DataSet-а. Абе искам да направя нещто като wrapper, нещо като TClientDataSet (само че не искам да ползвам TClientDataSet).
Да, това което предлагаш ме устройва напълно, дето се вика нещо като макрос се получава:))
А колкото за Ц-то - да от там съм свикнал да им викам структури:))
И понеже виждам че ме разбираш (и разбираш) да те питам още нещо ако може:)
Имам следния сценарий:
Имам един клас който съм наследил от TDataSet и той взима данни от друг(и) TDataSet (в случая от TIBDataSet)
класа Х наследява TDataSet за да мога лесно да го вържа към разни DB aware контроли (гридове и т.н). Докато го преписвах (наследявах) осъзнах че в новия клас дублирам паметта за записите (буферите) т.е. заделям още един път излишно буфери които пълня от друг датасет който също е заделил буфер за същия запис. Т.е. ненужно разхищение на памет. Въпроса ми е мога ли да ползвам някак директно буферите от source DataSet-а. Абе искам да направя нещто като wrapper, нещо като TClientDataSet (само че не искам да ползвам TClientDataSet).
Относно наследника на TDataSet
Може ли да се намеся и аз в разговора?...
В постинга си не си дал много информация защо искаш да ко направиш този "wrapper" на TIBDataSet и защо за целта да не можеш да ползваш TClientDataSet. Ако отговора на второто е заради лицензите - има две други решения. Първо има доста компоненти за "InMemory" DataSet (например TkbmMemTable), които са безплатни, open source и т.н., и второ - можеш да включиш CachedUpdates на TIBDataSet-а и да си манипулираш данните в него, без това да засяга базата данни (разбира се ако не викаш ApplyUpdates).
Ако имаш нужда да форматираш самите данни или да ги манипулираш по някакъв друг начин класа TField има много удобно събитие, което можеш да използваш за целта - OnGetText.
Това бе само ако догадките ми защо искаш да направиш wrapper на TIBDataSet са верни. Ти ще кажеш дали е така. Ако не - нека да вметна няколко думи за идеята ти за използване буферите на TIBDataSet-а. Според мен това е много нередно да го правиш. След такива изказвания обикновено се отваря дума за обектен модел, капсулация на данни и т.н. :-) Най-коректното според мен обаче е да се каже, че тези буфери не са предвидени да се ползват директно "отвън". Какво имам предвид - ти винаги можеш да си запазиш указател към паметта, където TIBDataSet-а си пази данните (друг е въпроса, как ще го получиш), но нямаш никаква гаранция за валидността му. Тя може да бъде нарушена по поне два начина. Първият е по време на работата на твоята програма. В IBX данните за отделните записи се пазят в последователна област от паметта, размерът на която се определя от пропъртито BufferChunks. След препълването на тази област се резервира нов блок памет по-голям с BufferChuks елемента, съдържанието на старите буфери се копира в новорезервираните, след което старият буфер се освобождава (за справка виж например тази статия) и разбира се твоят указател вече сочи към освободена памет. Това може да стане с редакцията/добавянето на записи или с fetch-ването на нови записи от базата (т.е. при изпълнението на Next например).
Вторият начин по който може да се развали работата е с ъпдейт на версията на IBX. Няма никаква гаранция, че в следващите версии вътрешната организация на записите няма да бъде променена. Така се излагаш на сериозен риск да ти се наложи да си преработваш софтуера.
Та след толкова много приказки от моя страна с две думи да кажа, че ако искаш да направиш wrapper около някакъв data set е препоръчително да достъпваш данните през предвидения интерфейс (Fields) за да избегнеш риска от главобол :-)
Ако те притеснява заеманата от TIBDataSet памет за буфериране на данните - обърни внимание на пропъртито Unidirectional. По този начин ще намалиш значително обена на заеманата от него памет лишавайки се от възможността да се разхождаш свободно напред-назад из dataset-а. И ако си организираш да прочетеш данните от TIBDataSet-а и да ги напълниш в твоя TDataSet наследник няма да имаш дублиране.
И накрая само искам да ти обърна внимание върху една статия, която поне на времето ми бе много полезна, когато и аз си пишех наследници на TDataSet. Ако си се ровил из нета по въпроса сигурно си я видял, но не пречи да я споменем за сведение
[линк]
Успех!
ПП Айде ако имаш желание разкажи с няколко думи какво се опитваш да направиш, че темата е интересна.
В постинга си не си дал много информация защо искаш да ко направиш този "wrapper" на TIBDataSet и защо за целта да не можеш да ползваш TClientDataSet. Ако отговора на второто е заради лицензите - има две други решения. Първо има доста компоненти за "InMemory" DataSet (например TkbmMemTable), които са безплатни, open source и т.н., и второ - можеш да включиш CachedUpdates на TIBDataSet-а и да си манипулираш данните в него, без това да засяга базата данни (разбира се ако не викаш ApplyUpdates).
Ако имаш нужда да форматираш самите данни или да ги манипулираш по някакъв друг начин класа TField има много удобно събитие, което можеш да използваш за целта - OnGetText.
Това бе само ако догадките ми защо искаш да направиш wrapper на TIBDataSet са верни. Ти ще кажеш дали е така. Ако не - нека да вметна няколко думи за идеята ти за използване буферите на TIBDataSet-а. Според мен това е много нередно да го правиш. След такива изказвания обикновено се отваря дума за обектен модел, капсулация на данни и т.н. :-) Най-коректното според мен обаче е да се каже, че тези буфери не са предвидени да се ползват директно "отвън". Какво имам предвид - ти винаги можеш да си запазиш указател към паметта, където TIBDataSet-а си пази данните (друг е въпроса, как ще го получиш), но нямаш никаква гаранция за валидността му. Тя може да бъде нарушена по поне два начина. Първият е по време на работата на твоята програма. В IBX данните за отделните записи се пазят в последователна област от паметта, размерът на която се определя от пропъртито BufferChunks. След препълването на тази област се резервира нов блок памет по-голям с BufferChuks елемента, съдържанието на старите буфери се копира в новорезервираните, след което старият буфер се освобождава (за справка виж например тази статия) и разбира се твоят указател вече сочи към освободена памет. Това може да стане с редакцията/добавянето на записи или с fetch-ването на нови записи от базата (т.е. при изпълнението на Next например).
Вторият начин по който може да се развали работата е с ъпдейт на версията на IBX. Няма никаква гаранция, че в следващите версии вътрешната организация на записите няма да бъде променена. Така се излагаш на сериозен риск да ти се наложи да си преработваш софтуера.
Та след толкова много приказки от моя страна с две думи да кажа, че ако искаш да направиш wrapper около някакъв data set е препоръчително да достъпваш данните през предвидения интерфейс (Fields) за да избегнеш риска от главобол :-)
Ако те притеснява заеманата от TIBDataSet памет за буфериране на данните - обърни внимание на пропъртито Unidirectional. По този начин ще намалиш значително обена на заеманата от него памет лишавайки се от възможността да се разхождаш свободно напред-назад из dataset-а. И ако си организираш да прочетеш данните от TIBDataSet-а и да ги напълниш в твоя TDataSet наследник няма да имаш дублиране.
И накрая само искам да ти обърна внимание върху една статия, която поне на времето ми бе много полезна, когато и аз си пишех наследници на TDataSet. Ако си се ровил из нета по въпроса сигурно си я видял, но не пречи да я споменем за сведение
[линк]
Успех!
ПП Айде ако имаш желание разкажи с няколко думи какво се опитваш да направиш, че темата е интересна.
Re: Help!!! Open Array parameters
Ами както и andrew_nikoloff каза, трудно ще се отговори
преди да уточниш, защото въпроса е малко мъгляво зададен.
Може би трябва да се тръгне от там - какво всъщност искаш
да постигнеш с твоя наследник на DataSet? Трябва да е
доста необичайно за да не можеш да ползваш вече наличните
компоненти които предлага делфи.
Единственото, което мога да предположа е, че искаш
нещо подобно на таблица в паметта, която да я пълниш
от външен датасорс. Нещо с което TClientDataSet чудесно
ще се справи. С какво не ти угоди TClientDataSet?
преди да уточниш, защото въпроса е малко мъгляво зададен.
Може би трябва да се тръгне от там - какво всъщност искаш
да постигнеш с твоя наследник на DataSet? Трябва да е
доста необичайно за да не можеш да ползваш вече наличните
компоненти които предлага делфи.
Единственото, което мога да предположа е, че искаш
нещо подобно на таблица в паметта, която да я пълниш
от външен датасорс. Нещо с което TClientDataSet чудесно
ще се справи. С какво не ти угоди TClientDataSet?
нещо като TClientDataSet
Може да ползваш и ADO без БД.
Още по добре виж kbmMemTable.
Още по добре виж kbmMemTable.
Re: Относно наследника на TDataSet
Първо благодаря за отговора.
Значи, нещата са много дълги и сложни и заплетени, и предполагам, че ще отегча хората...
Първо аз излъгах малко (за да не обяснявам на дълго и широко), за TIBDataSet. Всъщност тоя Wrapper class ми е необходим само за да мога по лесно да ползвам DB aware контроли. Ако TDataSource беше направен така че да може да се наследи щях да ползвам него но уви... Т.е. идеята ми (от която вече се отказах) беше wrapper-а да си взима данните от каквото и да е (не непременно от друг TDataSet)...
Системата е нещо като ERP. Имам ApplicationServer който не се връзва директно към Database а между тях има оше един layer който аз наричам Storage (TStorage да речем). AppServer-a очаква TStorage, или наследник на TStorage от който да взима данните (по установен протокол - серия от методи и т.н.). Самият TStorage не е много ясно от къде взима данните - той е базов абстрактен клас, неговите наследници взимат данни от някъде [TextFile..SQLServer]. Причината да ползвам междинен layer между AppSrv и DB е че системата не трябва да зависи от Phisical Storage или от точно определен вид бази данни. Пример: мода да имам TIBStorage, TMSSQLServerStorage, TOracleStorate, TMySQLStorage, TXMLStorage, TCSVStorage и т.н... Конкретния Storage стои в .bpl (package) и се зарежда според конфигурацията. TStorage има възможността да записва обекти "директно" (обектите който ползва AppServer) и разни други неща.
Пример за Storage:
-----------------------------------
TStorage = class;
TSQLStorage = class(TStorage);
TFIBStorage = class(TSQLStorage);
TFIBPlusStorage = class(TFIBStorage);
TStorage (Знае как да записва обектите) <
< TSQLStorage (добавя функционанност за запис в ANSI99 SQL Server) <
< TFIBStorage (съобразен със спецификите при Interbase,Firebird) <
< TFIBPlusStorage (конкретна имплементация с помоща на FIBPlus компонентите);
-----------------------------------
"API"-то на TStorage наподобява DBVCL в много отношения, но и в много се различава. Щеше ми се (понеже съм мързелив) да направя наследник на TDataSet към който да връзвам DB контроли, а той да си взима данните от Storage-a, но се отказах защото разликите се оказаха повече от приликите. Например навигацията при TDataSet (или изобщо при базите данни) запис напред, запис назад (first,next,prior...) не се връзва с навигацията в моята система (която е по скоро като да се разхождаш по "дърво")... абе беше доста тъпа идея. После мислех за TDataSetProvider което пак се оказа тъпа идея. И сега правя нещо като DataSource който да взима данни от Storage и да ги слага във визуални контроли. Нещо като mapper, binder...
Това е много накратко казано, но ме мързи да пиша защото е много (особено за сървъра, клиентите, връзката между тях и т.н.)
Това което казваш, че да правиш такива неща при обектно ориантираното програмиране е "анатема" е абсолюто вярно. Аз обаче понякога го правя с цел оптимизация или ако класа(овете) от които наследявам не са измеслени много добре (или поне на мен не ми се връзват с идеологията). Има и нещо друго - мързел:)
Значи, нещата са много дълги и сложни и заплетени, и предполагам, че ще отегча хората...
Първо аз излъгах малко (за да не обяснявам на дълго и широко), за TIBDataSet. Всъщност тоя Wrapper class ми е необходим само за да мога по лесно да ползвам DB aware контроли. Ако TDataSource беше направен така че да може да се наследи щях да ползвам него но уви... Т.е. идеята ми (от която вече се отказах) беше wrapper-а да си взима данните от каквото и да е (не непременно от друг TDataSet)...
Системата е нещо като ERP. Имам ApplicationServer който не се връзва директно към Database а между тях има оше един layer който аз наричам Storage (TStorage да речем). AppServer-a очаква TStorage, или наследник на TStorage от който да взима данните (по установен протокол - серия от методи и т.н.). Самият TStorage не е много ясно от къде взима данните - той е базов абстрактен клас, неговите наследници взимат данни от някъде [TextFile..SQLServer]. Причината да ползвам междинен layer между AppSrv и DB е че системата не трябва да зависи от Phisical Storage или от точно определен вид бази данни. Пример: мода да имам TIBStorage, TMSSQLServerStorage, TOracleStorate, TMySQLStorage, TXMLStorage, TCSVStorage и т.н... Конкретния Storage стои в .bpl (package) и се зарежда според конфигурацията. TStorage има възможността да записва обекти "директно" (обектите който ползва AppServer) и разни други неща.
Пример за Storage:
-----------------------------------
TStorage = class;
TSQLStorage = class(TStorage);
TFIBStorage = class(TSQLStorage);
TFIBPlusStorage = class(TFIBStorage);
TStorage (Знае как да записва обектите) <
< TSQLStorage (добавя функционанност за запис в ANSI99 SQL Server) <
< TFIBStorage (съобразен със спецификите при Interbase,Firebird) <
< TFIBPlusStorage (конкретна имплементация с помоща на FIBPlus компонентите);
-----------------------------------
"API"-то на TStorage наподобява DBVCL в много отношения, но и в много се различава. Щеше ми се (понеже съм мързелив) да направя наследник на TDataSet към който да връзвам DB контроли, а той да си взима данните от Storage-a, но се отказах защото разликите се оказаха повече от приликите. Например навигацията при TDataSet (или изобщо при базите данни) запис напред, запис назад (first,next,prior...) не се връзва с навигацията в моята система (която е по скоро като да се разхождаш по "дърво")... абе беше доста тъпа идея. После мислех за TDataSetProvider което пак се оказа тъпа идея. И сега правя нещо като DataSource който да взима данни от Storage и да ги слага във визуални контроли. Нещо като mapper, binder...
Това е много накратко казано, но ме мързи да пиша защото е много (особено за сървъра, клиентите, връзката между тях и т.н.)
Това което казваш, че да правиш такива неща при обектно ориантираното програмиране е "анатема" е абсолюто вярно. Аз обаче понякога го правя с цел оптимизация или ако класа(овете) от които наследявам не са измеслени много добре (или поне на мен не ми се връзват с идеологията). Има и нещо друго - мързел:)
Re: нещо като TClientDataSet
Мда, дано след всички обяснения прочете твоя отговор още веднъж. След цялата дискусия разбрах само че човека иска негово си ADO. Но пък може да го направи по-добре, така че няма лошо да се копа в тая насока.
чети и дишай по-леко
чети и дишай по-леко