Autor Beitrag
mcbain
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 60
Erhaltene Danke: 1



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 306
Erhaltene Danke: 14



BeitragVerfasst: 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



BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 60
Erhaltene Danke: 1



BeitragVerfasst: Fr 25.11.11 07:35 
Ich rede von keiner Komponente, sondern von Objekt-Attributen.
Bsp:

ausblenden 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
  //Hier soll dann eine Abfrage rein, die überprüft, ob das Attribut FSitze durch den User verändert wurde
  //Aber da eine Integer-Variable ja standardmäßig 0 ist, weiß man ja nicht, ob die 0 durch den User reingeschrieben wurde oder die 0 der Initialwert ist
  
end;

var auto: TAuto;
begin
  auto := TAuto.Create;
  auto.FSitze := 0;

  auto.TueEtwas();

end;
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19338
Erhaltene Danke: 1752

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: 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. :gruebel:
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:
ausblenden 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
      // das default hier dient dafür den Standardwert für den Objektinspektor festzulegen, wenn die Klasse dort angezeigt wird
  end;

constructor TAuto.Create;
begin
  FSitze := 1// im Konstruktor kannst du die Werte auf den Initialwert setzen
end;

procedure TAuto.TueEtwas;
begin

end;
mcbain Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 60
Erhaltene Danke: 1



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8553
Erhaltene Danke: 479

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 60
Erhaltene Danke: 1



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19338
Erhaltene Danke: 1752

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 60
Erhaltene Danke: 1



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: 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:
ausblenden volle Höhe 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:
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;

{ TNullable<T> }

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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19338
Erhaltene Danke: 1752

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Sa 26.11.11 13:54 
user profile icondelfiphan hat folgendes geschrieben Zum zitierten Posting springen:
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:
ausblenden volle Höhe 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:
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;

{ TNullable<T> }

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:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
var
  a: TNullable<TPoint>;
  b: TPoint;
begin
  a.Value := Point(100200);
  ShowMessage(FloatToStr(Point(200300).Distance(a)));
// EDIT:
Gerade getestet: Das geht erst ab Delphi XE 2, nicht mit XE oder früher.
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: 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:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
var
  I: TNullable<Integer>;
begin
  I := 5;
  ShowMessage(IntToStr(I));
end;
mcbain Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 60
Erhaltene Danke: 1



BeitragVerfasst: 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:

ausblenden 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