Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Variablen-Übergabe zwischen zwei Units (https://www.delphipraxis.net/193059-variablen-uebergabe-zwischen-zwei-units.html)

H.Bothur 15. Jun 2017 16:20

Delphi-Version: 10 Berlin

Variablen-Übergabe zwischen zwei Units
 
Moin,

ich bin mir gerade unsicher wie man es "richtig" macht :-)

Ich habe:

Programmunit (MainUnit) die ein ClientDataSet und eine Datenbank hat (CSV-Daten in Dataset importiert)
eine zweite Unit die auch eine Datenbank ansteuert.
Jetzt sollen per procedure Daten aus der zweiten Datenbank in die erste kopiert werden

jetzt gibt es für mich drei Varianten:

Delphi-Quellcode:
procedure LeseDaten(const: KundenNummer: out: Name1, Name2, Strasse, PLZ, Ort, Telefon, Telefax: String);
procedure LeseDaten(const: KundenNummer: out: KundenSatz: TStringList);
procedure LeseDaten(const: KundenNummer: out: KundenSatz: KundenRecord);
Die Variante 1 ist logisch - hat aber eben in diesem Fallsieben Variable
bei Variante 2 ist der Aufruf schön klar - ich muss aber erst alles in die StringList packen
bei Variante 3 ist der Aufruf auch schön klar - da muss ich aber erst alles in den record packen

Was ist denn in so einem Fall "State of the Art" ??

Gruß
Hans

Aviator 15. Jun 2017 16:25

AW: Variablen-Übergabe zwischen zwei Units
 
Ich glaube StateOfTheArt gibt es in dem Fall nicht wirklich. Aber am ehesten würde wohl Variante 3 mit dem Record oder als Instanz einer entsprechenden Klasse bzw. eines Interfaces gewählt werden. Vorteil dabei im Gegensatz zu Variante 1 ist, dass die Klasse/der Record erweitert werden könnte, sich aber an allen Stellen im Code, an dem die Klasse/der Record übergeben wird, nichts ändern würde.

Also meine Wahl wäre Variante 3 bzw. 4 mit Klassen.

Mavarik 15. Jun 2017 16:45

AW: Variablen-Übergabe zwischen zwei Units
 
Also ich würde ein

IDataview<TKunde> übergeben...

Als Wrapper für eine TKunden Classe die ein Interface hat für das LiveTime-Management.

Das / Die Interfaces sehen dann so aus:

Delphi-Quellcode:
  IDataView<T> = interface
    function GetData : T;
    function Reload : IDataView<T>;
    property Data : T read GetData;
  end;

  IDataViewList<T> = interface( IDataView < TList <T> > )
    function ReloadList : IDataViewList<T>;
  end;

  IPagedDataViewList<T> = interface( IDataViewList<T> )
    function ReloadPage: IPagedDataViewList<T>;
    function GetFirst: IPagedDataViewList<T>;
    function GetPrevious: IPagedDataViewList<T>;
    function GetPage( const PageIndex: Integer ): IPagedDataViewList<T>;
    function GetNext: IPagedDataViewList<T>;
    function GetLast: IPagedDataViewList<T>;

    function GetCount: Integer;
    function GetCurrent: Integer;
    property Count: Integer read GetCount;
    property Current: Integer read GetCurrent;
  end;
Mavarik

hoika 15. Jun 2017 16:49

AW: Variablen-Übergabe zwischen zwei Units
 
Hallo,
ich würde eine Klasse statt Record nehmen.
Derjenige, der die Daten haben will (Aufrufer) erzeugt die Klasse und gibt sie danach auch schön wieder frei.

himitsu 15. Jun 2017 16:49

AW: Variablen-Übergabe zwischen zwei Units
 
Zitat:

Delphi-Quellcode:
procedure LeseDaten(const: KundenNummer: out: KundenSatz: TStringList);

Wenn, dann ohne OUT.
Du gibst eine Instanz rein und die Funktion füllt sie nur.

Und nimm TStrings als Parameter, dann kann man irgendeinen TStrings-Nachfahren übergeben und ist nicht gezwungen immer nur TStringList zu nehmen.
z.B. Memo.Lines (das ist intern ein TMemoStrings).

SneakyBagels 15. Jun 2017 16:50

AW: Variablen-Übergabe zwischen zwei Units
 
Zitat:

ich würde eine Klasse statt Record nehmen.
Ob Klasse oder Record, da bin ich eher für Record. Warum weiß nicht nicht. Ist am Ende aber quasi dasselbe.
Was ich aber definitiv nicht nehmen würde, wäre ein Interface.

Mavarik 15. Jun 2017 16:58

AW: Variablen-Übergabe zwischen zwei Units
 
Zitat:

Zitat von SneakyBagels (Beitrag 1374614)
Was ich aber definitiv nicht nehmen würde, wäre ein Interface.

Ich würde NUR ein Interface nehmen und nie etwas anderes..

Zum einen kauft man sich das Reference-Counting zum 2. ist man von der Implementation unabhängig und kann die Units entkoppeln, was auch die Unitstests einfacher macht.

Mavarik

H.Bothur 15. Jun 2017 17:01

AW: Variablen-Übergabe zwischen zwei Units
 
Hi Maverick,

gute Idee - aber ... für mich ist das zu hoch :-( Mit Records habe ich schon mal gearbeitet - bei dem was Du geschrieben hast kann ich gerade mal raten was wofür sein kann. Da müsste ich viel mehr noch lernen.

Trotzdem - Vielen Dank !!!
Hans

Fritzew 15. Jun 2017 17:02

AW: Variablen-Übergabe zwischen zwei Units
 
Zitat:

Zitat von Mavarik (Beitrag 1374616)
Zitat:

Zitat von SneakyBagels (Beitrag 1374614)
Was ich aber definitiv nicht nehmen würde, wäre ein Interface.

Ich würde NUR ein Interface nehmen und nie etwas anderes..

Zum einen kauft man sich das Reference-Counting zum 2. ist man von der Implementation unabhängig und kann die Units entkoppeln, was auch die Unitstests einfacher macht.

Mavarik

Ich sage es ja nicht gerne aber Mavarik hat zu 100% Recht.

mjustin 15. Jun 2017 17:14

AW: Variablen-Übergabe zwischen zwei Units
 
Zwei Parameter sind zu viel :)

Delphi-Quellcode:
type
  IKunde = interface
  ...
 
function LeseDaten(const KundenNummer: string): IKunde;

Fritzew 15. Jun 2017 17:18

AW: Variablen-Übergabe zwischen zwei Units
 
Zitat:

Zitat von mjustin (Beitrag 1374619)
Zwei Parameter sind zu viel :)

Delphi-Quellcode:
type
  IKunde = interface
  ...
 
function LeseDaten(const KundenNummer: string): IKunde;

Kommt darauf an wer nachher für die Daten verantwortlich ist. Der Aufrufende oder der Aufrufen...

Ich würde das so machen:
Kunde muss vorher initialisiert sein:
Delphi-Quellcode:
function LeseDaten(const KundenNummer: string; Value : IKunde): boolean;
Kann ich dann einfach in Code benutzen mit

if LeseDaten('1000', localKunde) then
begin
end

oder auch
Delphi-Quellcode:
function LeseDaten(const KundenNummer: string; var Value : IKunde): boolean;

mjustin 15. Jun 2017 17:26

AW: Variablen-Übergabe zwischen zwei Units
 
Zitat:

Zitat von Fritzew (Beitrag 1374620)
Delphi-Quellcode:
function LeseDaten(const KundenNummer: string; var Value : IKunde): boolean;

Das var ist nicht notwendig, man kann auch über const Value: IKunde ein existierendes (leeres) Kundenobjekt übergeben, füllen, und an den Aufrufer zurückgeben. Warum sollte man erst ein Objekt erzeugen, es per var übergeben, und in der aufgerufen Methode LeseDaten dann ein neues Objekt erzeugen, und das übergebene Objekt durch es ersetzen?

SneakyBagels 15. Jun 2017 17:30

AW: Variablen-Übergabe zwischen zwei Units
 
Zitat:

gute Idee - aber ... für mich ist das zu hoch
Da stimme ich dir zu. Wie es aussieht, bist du rein hobbymäßig mit Delphi unterwegs. Da braucht man so hohen Kram nicht.

Nimm Records und damit hat sich das!
- einfach zu erstellen
- einfach zu erweitern
- relativ wenig Code
- verständlich

Fritzew 15. Jun 2017 17:33

AW: Variablen-Übergabe zwischen zwei Units
 
Zitat:

Zitat von mjustin (Beitrag 1374622)
Zitat:

Zitat von Fritzew (Beitrag 1374620)
Delphi-Quellcode:
function LeseDaten(const KundenNummer: string; var Value : IKunde): boolean;

Das var ist nicht notwendig, man kann auch über const Value: IKunde ein existierendes (leeres) Kundenobjekt übergeben, füllen, und an den Aufrufer zurückgeben. Warum sollte man erst ein Objekt erzeugen, es per var übergeben, und in der aufgerufen Methode LeseDaten dann ein neues Objekt erzeugen, und das übergebene Objekt durch es ersetzen?

Ja es ging mit ja nur darum die verschiedenen Möglichkeiten zu zeigen. Const in Interface Parametern würde ich aber nur dann verwenden wenn es wirklich zeitkritischer Code ist. Da man dadurch die Referenzzählung aushebelt kannn das teilweise zu unschönen Effekten führen. (Ist aber ein komplett anderes Thema ;-))
Was ich in Delphi wirklich vermisse ist die Möglichkeit wie in C++ Zuweisungen auszuwerten also z.B (Wunschdenken)

Delphi-Quellcode:
if (myKunde := GetKunde('1000')) <> nil then ...
Man darf ja noch träumen oder? :-)

Fritzew 15. Jun 2017 17:38

AW: Variablen-Übergabe zwischen zwei Units
 
Zitat:

Zitat von SneakyBagels (Beitrag 1374623)
Zitat:

gute Idee - aber ... für mich ist das zu hoch
Da stimme ich dir zu. Wie es aussieht, bist du rein hobbymäßig mit Delphi unterwegs. Da braucht man so hohen Kram nicht.

Nimm Records und damit hat sich das!
- einfach zu erstellen
- einfach zu erweitern
- relativ wenig Code
- verständlich

Entschuldige aber so eine Aussage ist einfach ....

Du benutzt Interfaces (Schnittstellen ) täglich mehrfach. Was ist ein Stromstecker? Interessiert es die Strombuchse ob da ein Toster
oder ein Drucker daran hängt? Ne die 2 wissen nur das sie zusammengesteckt werden können, 2 Leitungen fertig. Was dahinterhängt ist egal. Und genau das ist ein Interface. Warum auch immer das nicht immer alle abstrahieren können ist mir zu hoch.
Aber bitte lasse Aussagen wie hohen Kram einfach sein. Danke

mjustin 15. Jun 2017 17:50

AW: Variablen-Übergabe zwischen zwei Units
 
Zitat:

Zitat von Fritzew (Beitrag 1374625)

Const in Interface Parametern würde ich aber nur dann verwenden wenn es wirklich zeitkritischer Code ist. Da man dadurch die Referenzzählung aushebelt kannn das teilweise zu unschönen Effekten führen.

Die Referenzzählung wird dadurch nicht ausgehebelt sondern nur eine unnötige zusätzliche Referenzzählung vermieden. Ist also eine Optimierung.

Nur das hier darf man dann nicht: LadeDaten(TKunde.Create);

Dass dann die Referenzzählung nicht funktioniert, ist ein lang und gut bekannter Bug. (https://stackoverflow.com/a/7640979/80901)

Fritzew 15. Jun 2017 17:55

AW: Variablen-Übergabe zwischen zwei Units
 
Ja genau deshalb der Hinweis auf zeitkritischer Code:
Zitat:

Zitat von mjustin (Beitrag 1374629)
Zitat:

Zitat von Fritzew (Beitrag 1374625)

Const in Interface Parametern würde ich aber nur dann verwenden wenn es wirklich zeitkritischer Code ist. Da man dadurch die Referenzzählung aushebelt kannn das teilweise zu unschönen Effekten führen.

Die Referenzzählung wird dadurch nicht ausgehebelt sondern nur eine unnötige zusätzliche Referenzzählung vermieden. Ist also eine Optimierung.

Nur das hier darf man dann nicht: LadeDaten(TKunde.Create);

Dass dann die Referenzzählung nicht funktioniert, ist ein lang und gut bekannter Bug. (https://stackoverflow.com/a/7640979/80901)

Da man nie weis wie der Code benutzt wird... Optimierten nur dann wenn wirklich notwendig

Fritzew 15. Jun 2017 17:57

AW: Variablen-Übergabe zwischen zwei Units
 
Zitat:

Dass dann die Referenzzählung nicht funktioniert, ist ein lang und gut bekannter Bug. (https://stackoverflow.com/a/7640979/80901)
Nachtrag: Laut Embarcadero ist das kein Bug, (as designed) ;-)

mjustin 15. Jun 2017 18:15

AW: Variablen-Übergabe zwischen zwei Units
 
Zitat:

Zitat von Fritzew (Beitrag 1374631)
Zitat:

Dass dann die Referenzzählung nicht funktioniert, ist ein lang und gut bekannter Bug. (https://stackoverflow.com/a/7640979/80901)
Nachtrag: Laut Embarcadero ist das kein Bug, (as designed) ;-)

;-)

"as designed" ist eine Umschreibung für "wir müssten Teile des DCC neu designen, um diesen Effekt zu vermeiden" (wenn ich Remy Lebaus Kommentar richtig verstehe). Bei strings tritt das Problem nicht auf, DCC erzeugt für diese eine versteckte Variable.

SneakyBagels 15. Jun 2017 18:37

AW: Variablen-Übergabe zwischen zwei Units
 
Zitat:

Was dahinterhängt ist egal.
Im Gegensatz zu einer Steckdose muss man das in Delphi aber selber implementieren und im besten Falle auch verstehen.

Es gibt Leute die wollen keine Interfaces nutzen, fertig aus Ende der Geschichte.
Außerdem sind wir schon meilenweit von der Ausgangsfrage entfernt.

Der TE fragte, welche der von ihm DREI vorgestellten Möglichkeiten die beste ist. Interfaces standen nicht auf seiner Liste.
Ich verstehe nicht, wie man sich nie an die von den Themenerstellern gewünschten Codes halten kann und immer Gift (Interfaces) einfügen muss, was dann früher oder später wieder zu einem geschlossenen Thread führt.

Daher: bitte bleiben wir doch einfach bei den vom TE genannten Möglichkeiten.

H.Bothur 15. Jun 2017 19:50

AW: Variablen-Übergabe zwischen zwei Units
 
Zitat:

Zitat von SneakyBagels (Beitrag 1374623)
Zitat:

gute Idee - aber ... für mich ist das zu hoch
Da stimme ich dir zu. Wie es aussieht, bist du rein hobbymäßig mit Delphi unterwegs. Da braucht man so hohen Kram nicht.

Danke !!

Hans

TigerLilly 16. Jun 2017 08:59

AW: Variablen-Übergabe zwischen zwei Units
 
1 ist mühsam, wenn sich die Attribute ändern, dann ändern sich auch die Signaturen aller Methoden.
2 ist mühsam, weil du alles, was nicht string ist, hin+her konvertieren musst.
3 ist gut + elegant.

Du kannst natürlich auch, anstatt eine Methode zu haben, die die ganze Struktur liefert, eine Methode machen, die nur das zurück liefert, was du benötigst + per overload dir die Konvertierung sparen.

function ReadData(sFieldName:String):String;
function ReadData(sFieldName:String):Float; overload;
function ReadData(sFieldName:String):TDateTime; overload;

Jumpy 16. Jun 2017 09:46

AW: Variablen-Übergabe zwischen zwei Units
 
Ich weiß ja die genauen zusammenhänge nicht, drum machts vllt. keinen Sinn, aber ich schmeiß trotzdem mal ganz ketzerisch (weil verkoppelt und nicht testbar usw.) einfach noch eine 4. Möglichkeit ein:

Man kann auch einfach das ganze ClientDataset von A nach B übergeben und dann in B nur auf den aktuellen Datensatz zu greifen.

TigerLilly 16. Jun 2017 09:51

AW: Variablen-Übergabe zwischen zwei Units
 
Das ist schlechter Stil (weil verkoppelt und nicht testbar usw.) . :-/

Jumpy 16. Jun 2017 10:31

AW: Variablen-Übergabe zwischen zwei Units
 
Zitat:

Zitat von TigerLilly (Beitrag 1374671)
Das ist schlechter Stil (weil verkoppelt und nicht testbar usw.) . :-/

Deswegen meinte ich ja auch "ketzerisch". Wobei es da ja auch Ansätze gibt, durch die das nicht unbedingt nur schlecht sein muss: ColumbusEgg4Delphi

mschaefer 16. Jun 2017 12:13

AW: Variablen-Übergabe zwischen zwei Units
 
Moin zusammen,

da gibt es wohl keinen eindeutigen Weg. Aber es lohnt sich einen Blick auf Himitsu's himXML zu werfen. Die kann man gut in der Main Unit ablegen, zur Übergabe nutzen oder auch um den Status des Programms zu speichern. Da der Autor ja in der DP ist, gibt es vielleicht auch noch den ein oder anderen Tipp.

Grüße // Martin

SneakyBagels 16. Jun 2017 17:16

AW: Variablen-Übergabe zwischen zwei Units
 
Hierzu hätte ich eine technische Frage.
Angenommen eine Prozedur hat 100 Parameter (Records, Integers, Strings, Booleans).
Gibt es Performancevorteile, wenn man 1 statt 100 Parameter übergibt?

Ich hole noch weiter aus:
angenommen ich übergebe gar keine Parameter und fülle nur ein Record, welches ich dann später in dieser Prozedur verwende. Hat das irgendwelche Performancevorteile?

DeddyH 16. Jun 2017 18:22

AW: Variablen-Übergabe zwischen zwei Units
 
Wenn Du von 100 Parametern nur 1 übergibst, wird das nicht kompilieren.

SneakyBagels 16. Jun 2017 18:45

AW: Variablen-Übergabe zwischen zwei Units
 
Zitat:

Wenn Du von 100 Parametern nur 1 übergibst, wird das nicht kompilieren.
Ich meinte das anders.
Gegeben ist eine Prozedur A mit 1 Parameter und Prozedur B mit 100 Parametern.
Gibt es Performanceunterschiede zwischen A und B?

mschaefer 17. Jun 2017 22:45

AW: Variablen-Übergabe zwischen zwei Units
 
Minimal, jedenfalls im Vergleich zu einem Datenbankzugriff. Und ich bin immernoch Überzeugt dass sich ein Blick auf die xml-klasse lohnt. Wenn da sich die DB ändert muss man nicht die ganze Struktur der Übergabe ändern.

HolgerX 18. Jun 2017 07:38

AW: Variablen-Übergabe zwischen zwei Units
 
Hmm...

Zitat:

Zitat von mschaefer (Beitrag 1374778)
Minimal, jedenfalls im Vergleich zu einem Datenbankzugriff. Und ich bin immer noch Überzeugt dass sich ein Blick auf die xml-klasse lohnt. Wenn da sich die DB ändert muss man nicht die ganze Struktur der Übergabe ändern.

Wenn der Aufrufer davon Ausgeht, Äpfel zu erhalten, jedoch die Funktion (aufgrund der Datenbankänderung) nur Äpfel in die Struktur geben kann, wie kann das dann funktionieren?

Wenn der Aufrufer nicht sicher sein kann, was in welcher Struktur seitens der Funktion zurück geliefert wird, dann ist die Funktion meiner Meinung unbrauchbar..

Aus meiner Sicht ist der Aufruf der Funktion in UnitB aus UnitA einem API-Aufruf unter MS gleich. Hier MUSS sicher sein, dass beide Seiten bei den übergebenen Daten (in beide Richtungen) vom gleichen Sprechen, sowohl Inhalt, wie auch Form.

Somit ist es ein Gangbarer Weg Records oder Objekte zu Verwenden, jedoch nur, wenn beide Units auch mit der gleichen Definition arbeiten (Stichwort DLL-Funktionen).

Interfaces sind da eine Option, jedoch hängt das wohl eher von der Flexibilität/Komplexität der Funktion ab. Bei einfachen Aufrufen würde ich eher zu Records greifen.

Dynamische XML-Strukturen sind schön, aber auch hier müssen die Tags fix definiert werden, sonst kann weder Aufrufer noch FUnktion damit etwas anfangen.
Wenn diese Tags fix sind, dann können natürlich einzelne weggelassen werden, jedoch müsste auch dann definiert werden, was ein Weglassen bedeutet. Wenn es sich z.B. um einen String-Wert handelt, kann das aus Sicht der DB entweder um einen Leerstring ('') oder um einen NULL Wert handeln. Somit muss auch dies für den jeweiligen Wert definiert werden ;)

Uff.. So viele Definitionen und alles nur um eine Funktion aufzurufen ;)


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:42 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