En plus une procedure of object c'est deux 'pointeurs cachés' : celui de la procedure + celui de l'objet .
En plus une procedure of object c'est deux 'pointeurs cachés' : celui de la procedure + celui de l'objet .
salut
tu raconte n'importe quoi
je n'ai fait appel qu'à des methodes published donc verifier lors de la conpilation
mes appelles ne se font que par le MethodAddress
en fait elle ne cherche que des methode existante
le fait que tu passe @maprocedure c'est exactement la meme chose
la seul difference c'est que je le fait dynamiquement lors de l'utilisation
@+ Phil
gb_68, tu n'aurais pas confondu Record et Class, ceci est impossible bien sur ...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 TShaiMappingStruct = record FSetProc : TShaiMappingSetter; FShaiMappingStruct : TShaiMappingData; procedure SetProc (const Source, Destination: TDataSet );inline; end; { TShaiMappingStruct } procedure TShaiMappingStruct.SetProc(const Source, Destination: TDataSet); begin FSetProc(FShaiMappingStruct,Source, Destination); end;
une méthode d'objet ben c'est TMethod ... je vois pas pourquoi, vous n'êtes pas d'accord tous les deux, vous racontez la même chose non d'un point de vue différent ?
sinon anapurna, je n'ai plus de @ pour la méthode SetProc et la recherche par nom publié ne garanti pas la compilation de la table d'assoc, et le code objet est plus long impliquant allocation et libération contre un tableau constant qui finallement est dans le principe du RTTI qui ne sont que des constantes ...
voici le code final sans pointeur, sans @, et safe-compilation merci à vous deux
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153 // Mapping type TSourceDestinationMapping = (...censored ...); TSourceMappingData = record SourceName : string; // Champ dans la Table Source DestinationName: string; // Champ dans la Table Destination SourceValue: string; // Champ qui sera comparé au Champ Source DestinationValue: string; // Champ qui sera affecté au Champ Destination RelationName: string; // Champ dans la Table Source qui sert pour un Test end; TSourceMappingSetter = procedure(const Item: TSourceMappingData; const Source, Destination: TDataSet); TSourceMappingWrapper = record SetProc: TSourceMappingSetter; // Procédure d'Affectation du Champ Destination Data: TSourceMappingData; end; // Test si le Champ Destination est Vide, car on ne doit pas l'écraser function IsEmptyDest(DestinationField: TField): Boolean; begin Result := DestinationField.IsNull or (Trim(DestinationField.AsString) = ''); end; // Affectation Simple procedure StandardSetter(const Item: TSourceMappingData; const Source, Destination: TDataSet); var SourceField, DestinationField: TField; begin SourceField := Source.FindField(Item.SourceName); DestinationField := Destination.FindField(Item.DestinationName); if Assigned(SourceField) and Assigned(DestinationField) and not SourceField.IsNull and IsEmptyDest(DestinationField) then DestinationField.AsVariant := SourceField.AsVariant; end; // Affectation d'une Constante en fonction de la Valeur de la Source procedure TestConstSetter(const Item: TSourceMappingData; const Source, Destination: TDataSet); var SourceField, DestinationField: TField; begin SourceField := Source.FindField(Item.SourceName); DestinationField := Destination.FindField(Item.DestinationName); if Assigned(SourceField) and Assigned(DestinationField) and not SourceField.IsNull and IsEmptyDest(DestinationField) then begin if SourceField.AsString = Item.SourceValue then DestinationField.AsVariant := Item.DestinationValue; end; end; // Affectation en fonction de la Valeur d'un autre Champ de la Source procedure RelativeSetter(const Item: TSourceMappingData; const Source, Destination: TDataSet); var SourceField, DestinationField, RelationField: TField; begin SourceField := Source.FindField(Item.SourceName); DestinationField := Destination.FindField(Item.DestinationName); RelationField := Source.FindField(Item.RelationName); if Assigned(SourceField) and Assigned(DestinationField) and Assigned(RelationField) and not SourceField.IsNull and IsEmptyDest(DestinationField) then begin if RelationField.AsString = Item.SourceValue then DestinationField.AsVariant := SourceField.AsVariant; end; end; // Affectation Simple mais Retire le Point de l'ADICAP ou CIM10 procedure WithoutPointSetter(const Item: TSourceMappingData; const Source, Destination: TDataSet); var SourceField, DestinationField: TField; begin SourceField := Source.FindField(Item.SourceName); DestinationField := Destination.FindField(Item.DestinationName); if Assigned(SourceField) and Assigned(DestinationField) and not SourceField.IsNull and IsEmptyDest(DestinationField) then DestinationField.AsString := AnsiReplaceText(SourceField.AsVariant, '.', ''); end; const Source_MAPPING : array[TSourceDestinationMapping] of TSourceMappingWrapper = ( (SetProc: WithoutPointSetter; Data : (SourceName: 'censored'; DestinationName: 'censored'; )), (SetProc: WithoutPointSetter; Data : (SourceName: 'censored'; DestinationName: 'censored'; )), (SetProc: StandardSetter; Data : (SourceName: 'censored'; DestinationName: 'censored'; )), (SetProc: WithoutPointSetter; Data : (SourceName: 'censored'; DestinationName: 'censored'; )), (SetProc: WithoutPointSetter; Data : (SourceName: 'censored'; DestinationName: 'censored'; )), (SetProc: StandardSetter; Data : (SourceName: 'censored'; DestinationName: 'censored'; )), (SetProc: StandardSetter; Data : (SourceName: 'censored'; DestinationName: 'censored'; )), // Valeur Plus Significative que censored (SetProc: RelativeSetter; Data : (SourceName: 'censored'; DestinationName: 'censored'; SourceValue: 'O'; RelationName: 'censored')), (SetProc: StandardSetter; Data : (SourceName: 'censored'; DestinationName: 'censored'; )), (SetProc: StandardSetter; Data : (SourceName: 'censored'; DestinationName: 'censored'; )), (SetProc: TestConstSetter; Data : (SourceName: 'censored'; DestinationName: 'censored'; SourceValue: 'O'; DestinationValue: 'O')), (SetProc: StandardSetter; Data : (SourceName: 'censored'; DestinationName: 'censored'; )), (SetProc: StandardSetter; Data : (SourceName: 'censored'; DestinationName: 'censored'; )), // Valeur Plus Significative que censored (SetProc: StandardSetter; Data : (SourceName: 'censored'; DestinationName: 'censored'; )), (SetProc: TestConstSetter; Data : (SourceName: 'censored'; DestinationName: 'censored'; SourceValue: 'O'; DestinationValue: 'A')), (SetProc: StandardSetter; Data : (SourceName: 'censored'; DestinationName: 'censored'; )), (SetProc: TestConstSetter; Data : (SourceName: 'censored'; DestinationName: 'censored'; SourceValue: 'O'; DestinationValue: 'I')), (SetProc: StandardSetter; Data : (SourceName: 'censored'; DestinationName: 'censored'; )), (SetProc: StandardSetter; Data : (SourceName: 'censored'; DestinationName: 'censored'; )), (SetProc: StandardSetter; Data : (SourceName: 'censored'; DestinationName: 'censored'; )), (SetProc: StandardSetter; Data : (SourceName: 'censored'; DestinationName: 'censored'; )), (SetProc: StandardSetter; Data : (SourceName: 'censored'; DestinationName: 'censored'; )), (SetProc: StandardSetter; Data : (SourceName: 'censored'; DestinationName: 'censored'; )), (SetProc: StandardSetter; Data : (SourceName: 'censored'; DestinationName: 'censored'; )), (SetProc: StandardSetter; Data : (SourceName: 'censored'; DestinationName: 'censored'; )), (SetProc: StandardSetter; Data : (SourceName: 'censored'; DestinationName: 'censored'; )), (SetProc: StandardSetter; Data : (SourceName: 'censored'; DestinationName: 'censored'; )) ); procedure TfCensored.RecopieChampsEnCommun(Source, Destination: tEpcMyDataset); var iField: integer; iMapping: TSourceDestinationMapping; ... Editing: Boolean; begin Editing := Destination.State in [dsEdit, dsInsert]; if not Editing then Destination.Edit; // Travail sur la ligne en cours // Ancienne ou Nouvelle Version de Source ? if (GetGlobal('Source', 'VER_SUP_0999', 'N') = 'O') then begin // Copie des Champs de la Table Source vers une Autre Table selon le Mapping for iMapping := Low(iMapping) to High(iMapping) do Source_MAPPING[iMapping].SetProc(Source_MAPPING[iMapping].Data, Source, Destination); end else begin // Ancien Mapping (Corrigé ? ) for iField := 0 to Source.FieldCount - 1 do begin if Destination.FieldNum(Source.Fields[iField].FieldName) > 0 then begin if (Trim(Source.Fields[iField].AsString) <> '') and (Destination.FieldByName(Source.Fields[iField].FieldName).isNull or (Trim(Destination.FieldByName(Source.Fields[iField].FieldName).AsString) = '')) then begin if epcPos(Source.Fields[iField].FieldName, '...|...|...|...') then begin Destination.FieldByName(Source.Fields[iField].FieldName).AsString := AnsiReplaceText(Source.FieldByName(Source.Fields[iField].FieldName).AsString, '.', ''); end else begin Destination.FieldByName(Source.Fields[iField].FieldName).AsString := Source.FieldByName(Source.Fields[iField].FieldName).AsString; end; end; end; end; end; // Calcul ... Destination.Post(); if Editing then Destination.Edit(); end;
Non j'ai pas confondu record et class, j'ai oublié de le mettre dans la liste nouveautés Delphi 2005 ou Turbo Delphi ... (pour les record : procedures et fonctions membres, visibilité -public, private,... -, surcharge d'opérateurs ...).
Et bien d'autres http://blog.developpez.com/index.php...&c=1&tb=1&pb=1
Et oui une procedure of object c'est en interne un type TMethode, mais avec bien entendu de meilleurs contrôles à la compilation.
D'ailleurs en débogage sur un FProcSurObjet = procedure of object; on a :
Bon développement,
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 FProcSurObjet ( Project1.TObjetDefProc.Test , $A0DA00 ) |- Code $408FE0 |- Data $A0DA00
Oh, du Pseudo Objet dans les Record ??? en fait, un Record ça ne serait pas simplement un TObject déguissé genre "= record" et c'est comme "= class" en DELPHI 2005, ce qui ne serait pas surprenant puisque le file of record à été supprimé, et que la logique dot net tout protection bien chiante ne peut pas supporter la tricherie des record, copymemory ou autre ... avec D7, j'en suis bien loin, personnellement, je préfère éviter le Dot net, voulant aller dans l'industriel ou l'informatique bas niveau, je dois réapprendre le c\c++ et fuire le montre de MicroSoft qui fait en sorte de ne plus avoir de programmeur système en dehors des siens d'ici 40 ans (le business ça se planifie)
PS :
Pour une solution objet il y avait aussiavec pour la création :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 TSourceMappingData = class public SourceName : string; // Champ dans la Table Source DestinationName: string; // Champ dans la Table Destination SourceValue: string; // Champ qui sera comparé au Champ Source DestinationValue: string; // Champ qui sera affecté au Champ Destination RelationName: string; // Champ dans la Table Source qui sert pour un Test procedure MappingSetter( const Source, Destination: TDataSet) ;virtual; abstract; end; TSourceMappingDataSetter1 = class public procedure MappingSetter( const Source, Destination: TDataSet); end; TSourceMappingDataSetter2 = class public procedure MappingSetter( const Source, Destination: TDataSet); end;
mais la on ne peut plus changer la méthode après la création de l'objet (sauf transtypage sauvage TSourceMappingDataSetterX(Objet).MappingSetter, tenter de changer le pointeur de la Vtable )
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 var SourceMappingArray : array[indices] of TSourceMappingData; ... SourceMappingArray[1] := TSourceMappingDataSetter1 .Create; SourceMappingArray[2] := TSourceMappingDataSetter2 .Create; SourceMappingArray[3] := TSourceMappingDataSetter1 .Create; ...
La solution objet pose le problème du Create et du Free (il est indispensable en D7, en D2005, Garbage Collector à la Java\C# ?)
le code est donc plus long, moins agréable à maintenir, je trouve ...
Sinon, la VTable c'est du RTTI non ? donc c'est des constantes que l'on ne peut pas changer j'ai déjà voulu attaquer l'altération de SetProc d'un TPropInfo ... j'ai compris ensuite que c'était constant, cf http://www.developpez.net/forums/sho...d.php?t=264383
pour le RTTI, ce sujet http://www.developpez.net/forums/sho...d.php?t=108779 peut être consulté ça donne une idée ...
Les record restent alloués dans la pile (sauf si créé par new) et pas d'héritage possible ; c'est surtout du sucre syntaxique :
au lieu d'écrireOn peut écrire
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 TMonRecord = record ... end; function TMonRecord_Ajouter ( const A,B : TMonRecord ) : TMonRecord ; ... MonRecord := TMonRecord_Ajouter ( A ,B );
ou
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 TMonRecord = record ... function Ajouter ( const B : TMonRecord ) : TMonRecord ; end; ... MonRecord := A.Ajouter(B);
Le code généré sera équivalent, c'est surtout une question de goût.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 TMonRecord = record ... class operator Add ( const A,B : TMonRecord ) : TMonRecord ; end; ... MonRecord := A+B;
Pour les objets, c'est toujours dans le tas ; il faut donc effectivement faire un free (en win32, pas de gc), c'est pour ça qu'il n'y a pas de surcharge d'opérateurs pour les objet en win32 (en .Net si). Les nouveaux Delphi font toujours la distinction entre win32 et .net (perso j'utilise Turbo Delphi win32) ;
la compatibilité win32 est donc toujours assurée. Les ajouts de fonctionnalités ne se font que si cela est possible (interfaces implémentées par record, impossible sans gc (à cause gestion mémoire à la COM _addref ...) -> pas en win32).
Enfin a propos du pointeur de la Vtable : c'était plus une blague qu'une suggestion d'implémentation la Vtable est propre à une classe (donc il ne faut pas y toucher car elle est partagée par les objets de la classe), mais chaque objet possède son propre pointeur vers celle de sa classe (et vouloir le modifier n'est assurément pas une bonne idée).
Effectivement, personnellement, je n'utilise quasimet QUE des pointeurs sur Structure lorsqu'il s'agit de stocker une collection de structure avec une TList
sinon gb_68, on est pas tous en Delphi 2005, donc fait bien la distinction class et record en D7- car la surcharge d'opérateur ça n'existe que pour les variants (est c'est pas évident), les méthodes c'est que pour les objets ...
vouloir modifier la Vtable n'est pas possible, mais la consulter est utile !
Ce message a mis du temps à motiver les troupes mais ça fait débat entre nous trois ... lol
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager