[delphi] opvragen van type van object in lijst

Pagina: 1
Acties:

  • tharkun
  • Registratie: Augustus 2003
  • Laatst online: 01-01-2025
Ik heb een lijst met daarin of lijsten of objecten. Van deze hele structuur wil een een kopie maken. In deze kopie wil ik daarna dingen veranderen.
Het punt is dat als ik
code:
1
nieuwelijst := oudelijst;

doe alleen de pointers gekopiert worden. Dit is niet wat ik wil, want de lagere nivo's worden zo niet gekopiert.

Daarom heb ik een function CloneList gemaakt. Deze loopt alle items in een 
lijst af om ze te kopieren. Als oudelijst[i] een lijst is moet hij dus 
recursief clonelist aanroepen.
Maar dat is mijn probleem. Hoe weet ik of oudelijst[i] van het type tlist is?

volgens mij zou dat met de 'is' operator moeten kunnen maar als ik
code:
1
if oudelijst[i] is Tlist then

doe krijg ik een compiler error. (Operator not applicable to this operand type) 
Hoe moet het wel?

Voor grote problemen hebben we de computer


  • Delphi32
  • Registratie: Juli 2001
  • Laatst online: 00:56

Delphi32

Heading for the gates of Eden

TList bevat een lijst van pointers, geen objecten. Dus werkt de is-operator niet. Je hebt 2 alternatieven:
1. TList vervangen door TObjectList, dan werkt jouw code wel
2. cast: if TObject(list[i]) is TList then...

  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 19-05 12:05

Tomatoman

Fulltime prutser

Bekijk TList.Assign() en huiver. Zie de helpfiles voor uitleg.

Nu de is operator.
tharkun schreef op donderdag 23 december 2004 @ 14:15:
volgens mij zou dat met de 'is' operator moeten kunnen maar als ik
code:
1
if oudelijst[i] is Tlist then

doe krijg ik een compiler error. (Operator not applicable to this operand type)
Voor alle object classes (dus alles wat afstamt van TObject) genereert Delphi standaard run-time type information (RTTI). De is operator maakt van RTTI gebruik om de class van een object te bepalen.

Als je een willekeurige pointer loslaat op de is operator, wordt er - uitgaande van het adres waar die ponter naar verwijst - gezocht naar RTTI. Bij een willekeurige pointer gaat dat natuurlijk mis. In het ergste geval krijg je een access violation.

Met is kun je daarom niet bepalen of een pointer naar een class verwijst of niet. Sterker nog, er is geen enkele (nette) manier om dat uit te vinden. De programmeur moet er zelf voor zorgen dat hij kan herkennen of er een pointer naar een class of een pointer naar iets anders in de TList zit gestopt. De twee meest voor de hand liggende oplossingen:
• Sla alleen pointers van hetzelfde type in de lijst op (dus geen gemengde lijst).
• Sla alleen TObject descendants in de lijst op. Gebruik desnoods een wrapper class.

Zo'n wrapper class zou er als volgt kunnen uitzien:
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
type
  TPointerClass = class(TPersistent)
    FMijnPointer: Pointer;
  public
    constructor Create(AMijnPointer: Pointer);
  published
    property MijnPointer: Pointer read FMijnPointer write FMijnPointer;
  end;

...

constructor TPointerClass.Create(AMijnPointer: Pointer);
begin
  FMijnPointer := AMijnPointer;
end;
Je instantieert voor iedere pointer die je in de TList wilt stoppen een TPointerClass object. Die instantie stop je in de TList en niet de pointer zelf. Om de TPointerClass objecten na gebruik netjes op te ruimen kun je TList vervangen door TObjectList - zie de OwnsObjects property van TObjectList.

[ Voor 99% gewijzigd door Tomatoman op 23-12-2004 19:48 ]

Een goede grap mag vrienden kosten.


  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

We adore chaos because we like to restore order - M.C. Escher


Verwijderd

Een andere aanpak is er een standaard patroontje tegenaan te gooien: Composite.
Je kan dan een eigen klasse structuur opzetten. Maar natuurlijk kan je ook het Composite patroon van de VCL via TComponent gebruiken.

Mocht je zelf willen gaan klussen, dan is dit patroon onder andere hier beschreven:
http://www.vico.org/pages...seny/Pattern%20Composite/