Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Type-Problem (https://www.delphipraxis.net/42249-type-problem.html)

Igotcha 16. Mär 2005 11:08


Type-Problem
 
Hallo zusammen,

ich passe gerade ein von Hagen hier beschriebenes modulares Programmsystem auf meine Bedürfnisse an.

Allerdings habe ich mit folgender Funktionalität Probleme:

Delphi-Quellcode:
type
  TModularForm = class(TForm)
  protected
    function GetParam(const Name: String): Variant; virtual;
    procedure SetParam(const Name: String; Data: Variant); virtual;
  public
    class procedure Register;
 // wir erweitern nun unser gemeinsammes Basis Interface
    //class function FormularName: String; virtual; abstract;
    //class function MenuPath: String; virtual; abstract;
 
    property Param[Name: String]: Variant read GetParam write SetParam; // <--- hier
  end;

...

function TModularForm.GetParam(const Name: String): Variant;
begin
  Result := TypInfo.GetVariantProp(Self, Name);
end;

procedure TModularForm.SetParam(const Name: String; Data: Variant);
begin
  TypInfo.SetVariantProp(Self, Name, Data);
end;
Ich habe entgegen dem Beispiel noch die Unit "TypInfo" in die uses-Klausel mit aufgenommen, da das Beispiel ohne diese nicht funktioniert.

Allerdings erhalte ich dann für die angegebene Zeile nun ein:

Delphi-Quellcode:
[Error] FormMain.pas(26): Incompatible types
Gruß Igotcha

sniper_w 16. Mär 2005 11:21

Re: Type-Problem
 
Delphi-Quellcode:
 procedure SetParam(const Name: String; Data: Variant); virtual;
Das ist ein Fehler, IMHO.
Du solltest es so machen:
Delphi-Quellcode:
 procedure SetParam( Data: Variant); virtual;

Igotcha 16. Mär 2005 11:29

Re: Type-Problem
 
Hmmm, ich habe das gerade als "Clou" interpretiert, dass ich mit
Delphi-Quellcode:
procedure SetParam(const Name: String; Data: Variant); virtual;
quasi eine "Allround-Möglichkeit" habe, um Properties innerhalb des gesamten Modulgeflechts setzen zu können...

Gruß Igotcha

jim_raynor 16. Mär 2005 11:36

Re: Type-Problem
 
Muss Data nicht auch const sein?

Igotcha 16. Mär 2005 11:43

Re: Type-Problem
 
Zitat:

Zitat von jim_raynor
Muss Data nicht auch const sein?

Ändert leider nichts :-(

Der Cursor landet genau hinter dem "write" in der o.g. Zeile.

negaH 17. Mär 2005 07:07

Re: Type-Problem
 
Tja, ich wusste das auch nicht was Borland da wiedermal geändert hat, so müsste es gehen:

Delphi-Quellcode:

    function GetParam(const Name: String): Variant; virtual;
    procedure SetParam(const Name: String; const Data: Variant); virtual;
  public
    class procedure Register;

    property Param[const Name: String]: Variant read GetParam write SetParam;
  end;
Der Index einer Property, wenn er vom Typ LongString ist, muß anscheinend jetzt immer als const deklariert werden. Ansich ist das logisch, unlogisch ist nur das man zb. in D3 auch ohne const arbeiten konnnte (wenn ich mich recht erinnere).

Zitat:

quasi eine "Allround-Möglichkeit" habe, um Properties innerhalb des gesamten Modulgeflechts setzen zu können...
Ja, so war es auch gedacht :)

Gruß Hagen

Igotcha 17. Mär 2005 13:31

Re: Type-Problem
 
Funktioniert jetzt, danke!

Timelesk 16. Nov 2006 06:59

Re: Type-Problem
 
Hallo,

ich habe meinen Code auch von Hagen und hatte das selbe Problem.
Nun funktioniert das soweit unter Delphi2006.

Aber wie kann ich jetzt Werte übergeben?
Über einen Button im MainForm rufe ich das nach dem Laden des Formulars auf:
Delphi-Quellcode:
modul1.SetParam('test', Button1.Caption);
Und danach teste ich anhand eines weiteren Buttons im Modul, ob der Wert übergeben wurde:
Delphi-Quellcode:
label1.caption := string(ModularForm1.GetParam('test'));
Leider gibt er mir aber bereits bei SetParam diese Fehlermeldung aus: Eigenschaft test existiert nicht

Wo muss man denn das noch definieren?


Vielen Dank

Muetze1 16. Nov 2006 09:32

Re: Type-Problem
 
Zitat:

Zitat von negaH
Delphi-Quellcode:
    function GetParam(const Name: String): Variant; virtual;
    procedure SetParam(const Name: String; const Data: Variant); virtual;
  public
    class procedure Register;

    property Param[const Name: String]: Variant read GetParam write SetParam;
  end;

Ich habe eine Frage dazu: In der OH steht aber vermerkt, dass Property Getter/Setter nicht virtuell sein dürfen. Ich habe aufgrund dessen extra mein Design ändern müssen. Ist dies hinfällig?

negaH 16. Nov 2006 20:27

Re: Type-Problem
 
Hm, das wäre mir absolut neu. Mich interessiert als Refernez nur das was die RTTI und somit der Compiler kann. In TypInfo.pas kann man sehr wohl lesen, als verwendeter realer Source!!, das eine Property auch virtuelle Getter/Setter haben kann.

Das spielt aber auch keine Rolle wenn es nicht so wäre. Dann ändern wir es so um das die Getter/Stetter statisch sind und intern als Dispatcher an 2 virtuelle Methoden weiterreichen.

Mich würde aber mal interessieren WO du das in der OH gelesen haben willst. Weil es dort nicht explizit steht und nur Beispiele mit statischen Methoden drinenstehen, heist dies noch lange nicht das es nicht geht. Ich programmiere seit es Delphi gibt (genauer seit BP4.0) und eine Setter/Getter Methode konnte schon immer statisch oder virtuell aber nicht dynamisch und somit ergo auch keine Nachrichtenmethode eg. als message deklariert sein. Sie darf sogar eine abstrakte Methode sein, und damit eben auch virtuell (abstrakte statische Methoden machen keinen Sinn).

Aus Sicht der Logik ist es auch sinnvoll, wenn man schon überschreibbare Methoden kennt, die Setter/Getter Methoden, die ja wiederum nur ein weiteres Qualitätsmerkmal der OOP umsetzen -> Properties, ebenfalls virtualisieren zu können. Warum sollten gerade auf die neueren Properties nicht die Regeln der OOP gelten ? (das wäre ein unlogischer Schritt von Borland gewesen den ich wohl am meisten kritisieren würde). Das man die Getter/Setter nicht dynamisch deklarieren kann ist eine Frage von Effizienz im Code. Sie wären unnötig langsam und brächten keinen Vorteil da man zu 99.99% der Zeit eine Property mit Getter/Setter Methoden sofort implementiert, statt mit dem Ziele sie über dynamische Methoden erst viel später durchimplementieren zu wollen. Hier zählt also der Kompromis von Aufwand und Nutzen der gegen dynamsiche Setter/Getter spricht. Der Sinn einer dynamsichen Methode besteht in der OOP darin das der Initial Entwickler einen Schnittstellenrumpf vorgeben kann ohne diese real implementieren zu müssen. Im Falle der Properties sind dynmische Methoden absolut sinnfrei, bzw. zu 99.9% sinnfrei ;)
Das man dabei aber diese Methoden nicht als Messagemethoden deklarieren kann ist ebenfalls sinnvoll da sie mit einem Messaging nichts zu tuen haben. Davon abgesehen sind Messagemethoden eng verknüpft mit den dynamischen Methoden, infakt es sind dynamische Methoden mit explizierter Angabe der Slotnummer der DMT im Source (früher in BP konnte man die Slotnummer auch bei normalen dynamsichen Methoden vorgeben, heute geht dies nicht mehr, schade). Ergo: da dynamische Setter/Getter nicht gehen, können auch Messagemethoden nicht funktionieren.

Wie man sieht: die Regeln der OOP und wie die Borlanianer die VCL konstruiert haben unterwerfen sich zwingender Logik. Einer Logik die man selber nachvollziehen kann und mit der wir quasi schon erraten können was in der VCL geht oder nicht geht.

Ich schlage bei sowas immer vor: einfach selber mal ausprobieren statt sich einfach auf Meinungen Andere zu verlassen (davon gibts nämlich ne Menge Pseudowissen).

Gruß Hagen

negaH 16. Nov 2006 20:36

Re: Type-Problem
 
Zitat:

Leider gibt er mir aber bereits bei SetParam diese Fehlermeldung aus: Eigenschaft test existiert nicht

Wo muss man denn das noch definieren?
Und? existiert denn eine Property "Test" in deiner TForm Klasse ?

Die Setter/Getter Methode .SetParam() und .GetParam() sind deshalb virtuell weil der Entwickler die Möglichkeit hat ZWEI verschiedene Implementierungswege einzuschlagen.

1.) direkte Auswertung in den Getter/Setter Methoden der übergebenen Parameter. Das ist das was du in deiner .SetParam() Methode mit Label1.Caption := Data; gemacht hast. Du wertest den Parameter Index/Name garnicht selektiv aus.

2.) automatische Auswertung über Properties die über TypInfo und Variants erfolgt.


DU hast also in deine Methode .GetParam() die Methode 2. gewählt ohne jedoch eine Property "Test" zu deklarieren. Im Setter .SetParam() wählst du Methode 1. und damit mischt du zwei grunverschiedene Implementierungswege. Die übrigens nur ein Vorschlag meinerseits waren.

Gruß Hagen

Muetze1 17. Nov 2006 09:17

Re: Type-Problem
 
Zitat:

Zitat von negaH
Mich würde aber mal interessieren WO du das in der OH gelesen haben willst. Weil es dort nicht explizit steht und nur Beispiele mit statischen Methoden drinenstehen, heist dies noch lange nicht das es nicht geht.

Ich ziehe keine Rückschlüsse in der Form, dass wenn eins nicht geht, das Gegenteil dessen funktionieren muss. Ich programmiere seit Delphi 4 und hatte bisher auch virtuelle Property Getter/Setter verwendet (funktionierten auch), bis ich in der Hilfe folgendes gelesen hatte: (Thema: "Auf Eigenschaften zugreifen")
Zitat:

Zitat von OH
Handelt es sich bei FeldOderMethod um eine Methode, kann diese nicht überschrieben werden. Darüber hinaus müssen Zugriffsmethoden für eine als published deklarierte Eigenschaft die Standardaufrufkonventionen register verwenden.

Ich lese daraus, dass ich sie nicht überschreiben kann und somit soll.

Hawkeye219 17. Nov 2006 09:46

Re: Type-Problem
 
Die Delphi5-Hilfe enthält an dieser Stelle offenbar einen (Übersetzungs?)Fehler.

Zitat:

Zitat von Delphi6-Hilfe
Wenn FeldOderMethode eine Methode ist, kann sie nicht überladen werden. Zugriffsmethoden für eine als published deklarierte Eigenschaft müssen die Standard-Aufrufkonvention register verwenden.

Zitat:

Zitat von Delphi2006-Hlife
Wenn FeldOderMethode eine Methode ist, kann diese nicht dynamisch sein. Falls es sich um eine virtuelle Methode handelt, kann diese nicht überladen werden. Zugriffsmethoden für eine als published deklarierte Eigenschaft müssen die Standard-Aufrufkonvention register verwenden.

Gruß Hawkeye

Muetze1 17. Nov 2006 11:22

Re: Type-Problem
 
Ok, dann ist alles klar. Das mit dem überladen ist ja auch vollkommen nachvollziehbar. Ok, danke, dann wäre das geklärt. Nun ja, die Änderungen habe ich an dem Projekt nun schon gemacht, aber bei nächsten Projekten kann ich dann wieder virtuelle Getter/Setter nutzen (die ja, wie gesagt, einwandfrei funktioniert hatten - daher war ich damals recht erstaunt dies zu lesen).

Timelesk 17. Nov 2006 16:52

Re: Type-Problem
 
Hallo Hagen,

danke für deine Antwort.

Zitat:

Zitat von negaH
1.) direkte Auswertung in den Getter/Setter Methoden der übergebenen Parameter. Das ist das was du in deiner .SetParam() Methode mit Label1.Caption := Data; gemacht hast. Du wertest den Parameter Index/Name garnicht selektiv aus.

Hier habe ich der property "test" die Caption von Button1 zugewiesen, also doch Weg 2 mit Properties gewählt.

Hier mal meine beiden Funktionen:
Delphi-Quellcode:
{Lade übergebene Variable}
function TModulForm.GetParam(const Name: String): Variant;
begin
  Result := TypInfo.GetVariantProp(Self, Name);
end;

{Setze zu übergebende Variable}
procedure TModulForm.SetParam(const Name: String;const Data: Variant);
begin
  TypInfo.SetVariantProp(Self, Name, Data);
end;
Zitat:

Zitat von negaH
DU hast also in deine Methode .GetParam() die Methode 2. gewählt ohne jedoch eine Property "Test" zu deklarieren. Im Setter .SetParam() wählst du Methode 1. und damit mischt du zwei grunverschiedene Implementierungswege. Die übrigens nur ein Vorschlag meinerseits waren.

Ich habe gemerkt, dass ich die Property "test" wirklich nicht gesetzt hatte.
Nun funktioniert das soweit mit Zahlen und Boolschen Properties.
Aber bei Strings gibt mir Delphi beim Beenden des Programmes eine Zugriffsverletzung aus.

1. In der MainForm (Anker-Unit) rufe ich nach dem erstellen des Formulars des Moduls diesen Code auf: modul1.SetParam('VarString', 'Stringübergabe');
2. Im Modul ist das ganze so deklariert:
Delphi-Quellcode:
  TModulForm1 = class(TModulForm)
  protected
    function GetParam(const Name: String): Variant; override;
    procedure SetParam(const Name: String;const Data: Variant); override;
  private
    //Deklarierung der Parameter für GetParam und SetParam
    FVarString : String;
  published
    //Deklarierung der Parameter für GetParam und SetParam

    property VarString : String read FVarString write FVarString;
  end;

{...}

function TModulForm1.GetParam(const Name: String): Variant;
begin
  Result := inherited GetParam(Name);
end;

procedure TModulForm1.SetParam(const Name: String;const Data: Variant);
begin
  // da wir das schon in der Basisklasse getan haben also einfach
  inherited SetParam(Name, Data);
end;

{...}

//Aufruf erfolgt per Button in ein Label
bfAusgabe.Caption := GetParam('VarString');
Ich sehe dort keinen Fehler und trotzdem kommt eine EAccessViolation in module rtl100.bpl
Kommt aber nur, sofern ich SetParam ausgeführt habe! Wenn ich nur GetParam ausführe und das Programm beende, kommt keine Fehlermeldung.


Desweiteren bin ich noch am tüfteln, wie ich z.B. per Button im Modul die Caption des Moduls ändere.
Man könnte Caption := 'Neuer Modultitel'; schreiben, aber wie kann ich das über den Modulnamen + Caption machen (in Form von Modulname.Caption) ?


Vielen Dank für die Hilfe

gruß
Timelesk

negaH 17. Nov 2006 17:06

Re: Type-Problem
 
;) das meinte ich mit "traue niemals Leuten die nicht vom Fach sind". EIn Übersetzer versteht garnicht was er da übersetzt und der verantwortliche "Programmierer" hat garnicht die Zeit alles ins kleinste Detail zu überprüfen.

Deshalb zählen im Grunde die Dokumentationen in Form eines Sourcecodes, und es ist meine erste "Amtshandlung", wenn ich eine neue Delphi version bekomme, deren RTL Source zu lesen. Deshalb weis ich definitiv das Unit TypInfo.pas von allen Delphiversionen der Zugriff auf Property per RTTI virtuelle Methoden unterstützen.

Überladene Methoden (overload) können bei Property nicht gehen, warum auch. Das würde bedeuten das das nur Sinn macht wenn man auch überladene Properties deklararien könnte. Das macht höchstens Sinn bei indizierten Array[] Properties. da nur bei deren Getter/Setter ein Parameter zur eindeutigen Indentifizierung des overloads vorhanden ist. Bekannntlich kann Delphi ja keine Overloads auf Funktionen in deren Parametersignatur nur der Resulttype unterschiedlich ist. Das würde auf normale Getter/Setter Methoden dann zutreffen.

Wenn ichs mir aber recht überlege, dann wären überladene indizierbare Properties garnichtmal so schlecht. Sowas ginge dann

Delphi-Quellcode:
type
  THashTable = class
  private
    function GetItem(const Index: String): THashItem; virtual; overload;
    function GetItem(const Index: Int64): THashItem; virtual; overload;
...  
  public
    property Item[const Index: String]: THashItem read GetItem write SetItem; overload;
    property Item[const Index: Int64]: THashItem read GetItem write SetItem; overload;
  end;
Hm, andererseits nimmt man dann halt einen Variant als Index.

Gruß Hagen

negaH 17. Nov 2006 17:38

Re: Type-Problem
 
Gut, denn

Zitat:

ch sehe dort keinen Fehler und trotzdem kommt eine EAccessViolation in module rtl100.bpl
Kommt aber nur, sofern ich SetParam ausgeführt habe! Wenn ich nur GetParam ausführe und das Programm beende, kommt keine Fehlermeldung.
ich sehe in deinem Source ebenfalls keinen Fehler (du bist also nicht verrückt :) )

Vermutung meinerseits wäre es:

a.) .SetParam('VarString', xyz); achte mal darauf das der Name der Property exakt ist. Das sollte eigentlich egal sein ob man Groß/Klein schreibt aber man weis ja nie was Borland so alles in den Units verändert mit den Versionen.

b.) FormVariable.SetParam(); achte darauf das FormVariable auch ein gültiges TForm enthält

c.) Unit Variants eventuell "schei.e" ?

So oft arbeite ich nicht mit Varianten, aber ichw eis das je nach Delphiversionen es so einige Probleme geben sollte. Ich vermeide sie deshalb. Aber in Bezug auf mein Beispeil wäre sie die flexibelste Alternative. Ehrlicherweise muß ich zugeben das mein Beispiel aus den Erfahrungen eines parellelen Entwicktungsprozesses meines eigenen Modulsystemes entstand.

Gruß Hagen

Timelesk 17. Nov 2006 18:42

Re: Type-Problem
 
Hallo Hagen,

vielen Dank für die schneller Antwort.

Ich habe nun einfach mal in der TypInfo nach Variant gesucht und herausgefunden, dass die Funktionen GetPropValue und SetPropValue ebenfalls mit Varianten arbeiten und siehe da: Es funktioniert mit Strings!


Zitat:

b.) FormVariable.SetParam(); achte darauf das FormVariable auch ein gültiges TForm enthält
Du meinst sicherlich TModulForm, also die Ableitung von TForm, oder?
Und genau das ist ja mein Problem:
im Hauptformular (in der auch die abgeleitete Klasse steht) wird ja das Package geladen und die Form über CreateModuleForm erstellt:
Delphi-Quellcode:
var modul1: TModulForm;
begin
  {...}
  modul1 := CreateModuleForm('TModulForm1');
end;
Jetzt kann ich von der Hauptform aus modul1.WindowState := wsMaximized schreiben und das klappt auch ganz schön :)
Aber im Modul selbst, wie kann ich dort das Formular ansprechen?
modul1 ist dort ja nicht registriert und wenn ich einfach ne Variable registrier ModulForm1 : TModulForm1, dann ist das ja nicht die Variable, welche auf mein Modul-Formular zeigt und ändert dementsprechend auch nichts ab.
Aber genau das möchte ich erreichen, dass ich im Modul selbst das Formular des Moduls ansprechen kann.

Ich hoffe, das war jetzt verständlich ;)


Vielen Dank

gruß
Timelesk

negaH 18. Nov 2006 10:06

Re: Type-Problem
 
Im Modul selber greifst du OOP konform zu, dh. immer über Self. Niemals über die globale Variable ModulForm1: TModulForm1, da diese ja garnicht mehr benutzt wird und zudem ist der Zugriff, egal ob Modulbasiert oder in normalen Delphi Anwendung, über diese Variable generell kontraproduktiv. Wenn man sowas denoch benötigt muß man sich eben bessere Wege einfallen lassen als Programierer. Denn benutzt man diese Variable dann verhindert man damit das multiple Erzeugen von mehreren Formularen der gleichen Instanz.

Gruß Hagen


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:39 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz