| Autor |
Beitrag |
mcbain
      
Beiträge: 60
Erhaltene Danke: 1
|
Verfasst: Do 24.11.11 15:23
Hallo,
ich habe eine simple Frage:
Ist es möglich in Delphi zu erkennen, ob ein Attribut zuvor gesetzt wurde?
Ich will nämlich gewisse Schritte einleiten, wenn das Attribut gesetzt wurde vom User.
Wurde die Variable vom User zuvor nicht gesetzt, so soll mein Programm das Attribut auch nicht auswerten.
Geht das einfach zu lösen, oder muss ich für jedes Attribut ein zusätzliches boolsches Attribut ala "Attribut_Set" einführen um dies herauszufinden?
Wäre nett, wenn mir jemand dies kurz beantworten könnte.
Vielen Dank.
gruß
mc
|
|
rushifell
      
Beiträge: 306
Erhaltene Danke: 14
|
Verfasst: Do 24.11.11 17:32
Meinst Du soetwas wie: "Wollen Sie die Änderungen speichern?" Ich mach das folgendermaßen: Ich schreibe die Daten beim Programmstart in einen Buffer (Array of Byte; Array of Boolean). Am Ende schreibe ich die Daten in einen zweiten Buffer und vergleiche einfach beide miteinander. Bei einem Unterschied kommt die Rückfrage, ob man die Änderungen speichern möchte.
|
|
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Do 24.11.11 18:36
Kommt drauf an was du für eine Komponente benutzt. Das TMemo kann sich merken, wenn sich was ändert. Darauf kann man reagieren. Werde mal etwas konkreter.
|
|
mcbain 
      
Beiträge: 60
Erhaltene Danke: 1
|
Verfasst: Fr 25.11.11 07:35
Ich rede von keiner Komponente, sondern von Objekt-Attributen.
Bsp:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24:
| TAuto = class(Tobject) private FSitze: integer; procedure TueEtwas(); published Sitze: integer read FSitze write FSitze; end; ...
procedure TAuto.TueEtwas(); begin end;
var auto: TAuto; begin auto := TAuto.Create; auto.FSitze := 0;
auto.TueEtwas();
end; |
|
|
jaenicke
      
Beiträge: 19338
Erhaltene Danke: 1752
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Fr 25.11.11 09:09
Ein Attribut wird in eckigen Klammern vor die Quelltextzeile gesetzt oder dient zur Definition der Sichtbarkeit (private, public, ...). Was du meinst sind Eigenschaften. (In anderen Sprachen wie Java wird der Begriff aber durchaus auch für Eigenschaften benutzt, in Delphi und C# ist das nicht üblich. In Java nennen sich Attribute dafür Annotationen.)
Ob eine Eigenschaft gesetzt ist, lässt sich in der Tat nicht feststellen, so dass du dir das einzeln merken musst.
Allerdings hatte ich dafür noch nie die Notwendigkeit.
Ich meine, wenn du jetzt damit rechnest, dann musst du doch einen Standardwert benutzen, oder? Und das sollte dann schlicht der sein, der standardmäßig in der Eigenschaft gesetzt ist. Um bei deinem Beispiel zu bleiben: Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| TAuto = class(TObject) private FSitze: Integer; procedure TueEtwas(); published constructor Create; property Sitze: Integer read FSitze write FSitze default 1; end;
constructor TAuto.Create; begin FSitze := 1; end;
procedure TAuto.TueEtwas; begin
end; |
|
|
mcbain 
      
Beiträge: 60
Erhaltene Danke: 1
|
Verfasst: Fr 25.11.11 10:03
Alles klar danke für die Antwort.
Ich habe eine Objectliste, welche ich an eine Methode übergebe. Diese Methode baut aus den einzelnen Objekten und deren Eigenschaften/Subobjekte einen XML-String zusammen. Wenn nun die Eigenschaft FSitze vom User nicht gesetzt wurde, wird bspw. trotzdem für FSitze der Tag <sitze>0</sitze> generiert, obwohl der Tag im XML eigentlich nicht vorkommen dürfte, da er ja vom User nicht gesetzt wurde. Aber da integer default auf 0 steht...
Aber dann mache ich es halt über SetMethoden, die zusätzlich für jede relevante Eigenschaft eine zusätzliches boolsche Eigenschaft setzen.
|
|
Gausi
      
Beiträge: 8553
Erhaltene Danke: 479
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Fr 25.11.11 10:24
Dann initialisiere doch die Eigenschaften mit einem ungültigen Wert (z.B. -1, 0, High(Integer), ...) und überprüfe in der XML-Erzeuge-Methode, ob die Werte gültig sind oder nicht.
_________________ We are, we were and will not be.
|
|
mcbain 
      
Beiträge: 60
Erhaltene Danke: 1
|
Verfasst: Fr 25.11.11 10:59
Das mit dem initialisieren habe ich mir auch schon überlegt, wäre auf jeden Fall weniger Schreibarbeit, man muss natürlich sicherstellen, dass man die Eigenschaften auf einen Wert festlegt, der wirklich nie vorkommen kann.
Ich werde das auch mal ausprobieren.
Vielen Dank nochmal.
|
|
jaenicke
      
Beiträge: 19338
Erhaltene Danke: 1752
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Fr 25.11.11 11:19
Geht es darum, dass ein kleinerer XML-String entsteht? Denn vom Prinzip her sollte es ja kein Problem sein, wenn diese Angaben auch enthalten sind, vorausgesetzt es wird der Defaultwert vorher gesetzt. Denn irgendein Wert muss ja auch benutzt werden, wenn die Angabe nicht gesetzt ist. Umgekehrt könntest du alle Werte herauslassen, die ohnehin dem Standardwert entsprechen.
(Es sei denn vom reinen Setzen hängt mehr als der reine Wert ab.)
|
|
mcbain 
      
Beiträge: 60
Erhaltene Danke: 1
|
Verfasst: Fr 25.11.11 11:39
Das sind schon teilweise größere XML-Strings die entstehen.
Ich kommuniziere über einen Webservice mit den XML-Strings. Wenn ich eine Eigenschaft bei mir setze, wird er beim Empfänger so reingeschrieben. Setze ich aber die Eigenschaft FSitze nicht, so würde im XML-Request trotzdem <sitze>0</sitze> an den Empfänger geschickt. Dies würde dazu führen, dass meine zuvor beim Empfänger gespeicherten FSitze überschrieben würden.
Deshalb muss ich vorher abklären, ob <sitze> enthalten sein muss oder nicht.
@Gausi: Das mit dem initiieren über den Konstruktor funktioniert aber leider nicht mit Boolschen werten. Da es dabei nur 2 Möglichkeiten gibt, und beide valide sind im XML.
|
|
delfiphan
      
Beiträge: 2684
Erhaltene Danke: 32
|
Verfasst: Sa 26.11.11 13:08
Wenn du ausser einem Boolean-Wert auch einen "null" Wert haben willst, kannst du ja ein Nullable-Konstrukt verwenden. Könnte so aussehen:
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:
| type TNullable<T: record> = record private FValue: T; FHasValue: Boolean; function GetValue: T; procedure SetValue(const Value: T); public property Value: T read GetValue write SetValue; property HasValue: Boolean read FHasValue; procedure SetNull; end;
function TNullable<T>.GetValue: T; begin if not FHasValue then raise EInvalidOperation.Create('No value has been set.'); Result := FValue; end;
procedure TNullable<T>.SetNull; begin FHasValue := False; FValue := default(T); end;
procedure TNullable<T>.SetValue(const Value: T); begin FValue := Value; FHasValue := True; end; |
Schön wär noch gewesen, wenn man den Implicit Operator hätte implementieren dürfen, scheint aber nicht zu gehen.
Alternativ dazu könnte man Variants verwenden, das wäre aber sicher zweite Wahl...
|
|
jaenicke
      
Beiträge: 19338
Erhaltene Danke: 1752
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Sa 26.11.11 13:54
delfiphan hat folgendes geschrieben : | | Schön wär noch gewesen, wenn man den Implicit Operator hätte implementieren dürfen, scheint aber nicht zu gehen. |
Doch, das sieht dann so aus, funktioniert bei mir problemlos: 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:
| type TNullable<T: record> = record private FValue: T; FHasValue: Boolean; function GetValue: T; procedure SetValue(const Value: T); public property Value: T read GetValue write SetValue; property HasValue: Boolean read FHasValue; procedure SetNull; class operator implicit(const Value: TNullable<T>): T; end;
function TNullable<T>.GetValue: T; begin if not FHasValue then raise EInvalidOperation.Create('No value has been set.'); Result := FValue; end;
class operator TNullable<T>.implicit(const Value: TNullable<T>): T; begin Result := Value.Value; end;
procedure TNullable<T>.SetNull; begin FHasValue := False; FValue := default(T); end;
procedure TNullable<T>.SetValue(const Value: T); begin FValue := Value; FHasValue := True; end; | Getestet mit: Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| var a: TNullable<TPoint>; b: TPoint; begin a.Value := Point(100, 200); ShowMessage(FloatToStr(Point(200, 300).Distance(a))); | // EDIT:
Gerade getestet: Das geht erst ab Delphi XE 2, nicht mit XE oder früher.
|
|
delfiphan
      
Beiträge: 2684
Erhaltene Danke: 32
|
Verfasst: Sa 26.11.11 15:34
Wie du siehst: ich bin noch nicht so weit
Die Fehlermeldung schien mir sowieso etwas merkwürdig.
Übrigens: Den Implicit-Operator könnte man in beide Richtungen implementieren, dann kannst du gleich sowas machen:
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| var I: TNullable<Integer>; begin I := 5; ShowMessage(IntToStr(I)); end; |
|
|
mcbain 
      
Beiträge: 60
Erhaltene Danke: 1
|
Verfasst: Di 29.11.11 12:09
Vielen Dank für eure Antworten.
Ich habe das ganze Bool-Problem nun mit einem eigenen Record gelöst.
Sieht dann so aus in etwa:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| MyBool = record private FBool: Boolean; FBool_Specified: boolean; procedure SetValue(aValue: boolean);
public property Bool_Specified: boolean read FBool_Specified; property Bool: boolean read FBool write SetValue; end;
...
procedure MyBool .SetValue(aValue: Boolean); begin self.FBool := aValue; Self.FBool_Specified := true; end; |
Jetzt kann ich über "Bool_Specified" abfragen, ob der User den Wert in "Bool" gesetzt hat.
Ansonsten arbeite ich jetzt mit Konstruktoren, die meine Eigenschaften mit unmöglichen Default-Werten belegen. Bei der XML-Erzeugung wird überprüft, ob der Eigeschafts-Wert ungleich dem Default-Wert für diesen Typ ist. Falls true, wird er in den XML-String geschrieben, ansonsten eben nicht.
Gruß
mc
|
|