Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Codezeile in Funktion umwandeln mit Schwierigkeiten (https://www.delphipraxis.net/192409-codezeile-funktion-umwandeln-mit-schwierigkeiten.html)

a.def 16. Apr 2017 10:11

Codezeile in Funktion umwandeln mit Schwierigkeiten
 
Ich habe gerade eine Gedankenslücke und weiß nicht weiter.
Ich habe eine Codezeile wie diese hier

Delphi-Quellcode:
var
 aMode: TModes;
begin
 aMode := TEnumFunctions.GetValue<TModes>(IniF.ReadString(sCurrentSection, TEnumFunctions.GetName(TIni_Idents.mode), TEnumFunctions.GetName(TModes.mManual)));
 // ...

 // Resultat in der Ini-Datei
 // [section-name]
 // mode=mManual

 // Das versuche ich zu erreichen..
 // aMode = ReadEnum(TIni_Idents.mode, TModes);
Dasselbe habe ich auch für andere Enum-Typen.
Wie kann ich daraus eine Funktion schreiben, die alle meine Enum-Typen annehmen kann?

Uwe Raabe 16. Apr 2017 10:38

AW: Codezeile in Funktion umwandeln mit Schwierigkeiten
 
Zitat:

Zitat von a.def (Beitrag 1367850)
Wie kann ich daraus eine Funktion schreiben, die alle meine Enum-Typen annehmen kann?

Etwas so?
Delphi-Quellcode:
function ReadFromIni<T>(IniF: TCustomInifile; const sCurrentSection: string; Ident: TIni_Idents; const Default: T): T;
begin
  Result := TEnumFunctions.GetValue<T>(IniF.ReadString(sCurrentSection, TEnumFunctions.GetName(Ident), TEnumFunctions.GetName<T>(Default)));
end;

Der Aufruf wäre dann:
Delphi-Quellcode:
begin
  aMode := ReadFromIni<TModes>(IniF, sCurrentSection, TIni_Idents.mode, TModes.mManual);
end;

Wenn das Inifile und die Section im Scope der Funktion bekannt sind, kann man die Parameter dafür auch weglassen.

a.def 16. Apr 2017 10:49

AW: Codezeile in Funktion umwandeln mit Schwierigkeiten
 
Soweit war ich tatsächlich noch nicht. Aber mit dem ReadFromIni<T> hatte ich dann ja wohl schon recht.
Nur habe ich es wieder gelöscht, da der Editor es rot unterstreicht, obwohl Generics.Collections in der Uses-Klausel steht.

Edit
Fehlerquelle gefunden. Ich wusste nicht, dass solche Funktionen und Prozeduren eine Deklaration im Unit-Kopf verlangen.

Mein Resultat in meiner eigenen ini-Klasse
Delphi-Quellcode:
type
 TMemIniFile = class(IniFiles.TMemIniFile)
 ...
 function ReadEnum<T>(const Section: string; const Ident: TIniSettings; const Default: T): T;
 procedure WriteEnum<T>(const Section: string; const Ident: TIniSettings; Value: T);
 ...

function TMemIniFile.ReadEnum<T>(const Section: string; const Ident: TIniSettings; const Default: T): T;
begin
 Result := TEnumFunctions.GetValue<T>(ReadString(Section, TEnumFunctions.GetName(Ident), TEnumFunctions.GetName<T>(Default)));
end;

procedure TMemIniFile.WriteEnum<T>(const Section: string; const Ident: TIniSettings; Value: T);
begin
 WriteString(Section, TEnumFunctions.GetName(Ident), TEnumFunctions.GetName<T>(Value));
end;
TEnumFunctions
Delphi-Quellcode:
type
 TEnumFunctions = record
  ...
  class function GetName<T>(AValue: T): string; static;
  class function GetValue<T>(AValue: string): T; static;
  ...

class function TEnumFunctions.GetName<T>(AValue: T): string;
begin
 Result := System.Rtti.TRttiEnumerationType.GetName(AValue);
end;

class function TEnumFunctions.GetValue<T>(AValue: string): T;
var
 Temp: Integer;
 PTemp: Pointer;
begin
 Temp := GetEnumValue(TypeInfo(T), AValue);
 if Temp < 0 then
  Temp := 0; // gebe 0 statt 255 zurück im Falle, dass AValue nicht existiert
 PTemp := @Temp;
 Result := T(PTemp^);

 // Result := System.Rtti.TRttiEnumerationType.GetValue<T>(AValue);
end;

a.def 16. Apr 2017 12:18

AW: Codezeile in Funktion umwandeln mit Schwierigkeiten
 
Eine Frage habe ich dann noch :pale:

Ginge auch das hier irgendwie?
Delphi-Quellcode:
procedure WriteEnum<T>(const Section: string; const Ident: T; Value: T);
Also Ident: T;? Dann wäre ich nicht auf einen Enum-Typen festgelegt.

Der Compiler sagt mir leider etwas unverständlich
Zitat:

E2532 Generisches Typargument konnte aus den unterschiedlichen Argumenttypen für Methode 'WriteEnum' nicht abgeleitet werden

Uwe Raabe 16. Apr 2017 13:19

AW: Codezeile in Funktion umwandeln mit Schwierigkeiten
 
Zitat:

Zitat von a.def (Beitrag 1367857)
Also Ident: T;? Dann wäre ich nicht auf einen Enum-Typen festgelegt.

Soll denn Ident vom selben Typ sein wie Value? Ich denke wohl nicht. Wenn es zwei unterschiedliche Typen sind, dann muss man das auch so deklarieren:

Delphi-Quellcode:
procedure WriteEnum<T,T2>(const Section: string; const Ident: T2; Value: T);

a.def 16. Apr 2017 13:33

AW: Codezeile in Funktion umwandeln mit Schwierigkeiten
 
Scheint aber verdammt kompliziert zu sein oder ich stelle mich doof an.

Delphi-Quellcode:
function TMemIniFile.ReadEnum<T, T2>(const Section: string; const Ident: T2; const Default: T): T;
begin
 Result := TEnumFunctions.GetValue<T>(ReadString(Section, TEnumFunctions.GetName<T2>(Ident), TEnumFunctions.GetName<T>(Default)));
end;

//

aJclCompressionMethod := IniF.ReadEnum<TIniSettings, TJclCompressionMethod>(sCurrentSection, TIniSettings.zipcompression, TJclCompressionMethod.cmDeflate);
Zitat:

E2250 Es gibt keine überladene Version von 'TMemIniFile.ReadEnum<_enums.TIniSettings,JclCompr ession.TJclCompressionMethod>', die man mit diesen Argumenten aufrufen kann
Aber ich glaube es nun kapiert zu haben. Die Angabe in Klammern <T> ist wohl dazu da um der Funktion mitzuteilen, um welche Typen es sich handelt.
Dann sieht mein Konstrukt nun so aus und statt 6 Methoden habe ich nun nur noch 4
Delphi-Quellcode:
function TMemIniFile.ReadEnum<T>(const Section: string; const Ident: T; const Default: T): T;
begin
 Result := TEnumFunctions.GetValue<T>(ReadString(Section, TEnumFunctions.GetName(Ident), TEnumFunctions.GetName<T>(Default)));
end;

procedure TMemIniFile.WriteEnum<T>(const Section: string; const Ident: T; Value: T);
begin
 WriteString(Section, TEnumFunctions.GetName(Ident), TEnumFunctions.GetName<T>(Value));
end;

function TMemIniFile.ReadEnum<T, T2>(const Section: string; const Ident: T; const Default: T2): T2;
begin
 Result := TEnumFunctions.GetValue<T2>(ReadString(Section, TEnumFunctions.GetName<T>(Ident), TEnumFunctions.GetName<T2>(Default)));
end;
// => aMode := IniF.ReadEnum<TIniSettings, TModes>(sCurrentSection, TIniSettings.mode, TModes.mManual);

procedure TMemIniFile.WriteEnum<T, T2>(const Section: string; const Ident: T; Value: T2);
begin
 WriteString(Section, TEnumFunctions.GetName<T>(Ident), TEnumFunctions.GetName<T2>(Value));
end;
// => IniF.WriteEnum<TIniSettings, TModes>(sCurrentSection, TIniSettings.mode, TModes.mManual);

Uwe Raabe 16. Apr 2017 14:15

AW: Codezeile in Funktion umwandeln mit Schwierigkeiten
 
Zitat:

Zitat von a.def (Beitrag 1367862)
Aber ich glaube es nun kapiert zu haben. Die Angabe in Klammern <T> ist wohl dazu da um der Funktion mitzuteilen, um welche Typen es sich handelt.

Das ist richtig! Es ist in der Regel auch notwendig die Typen beim Aufruf anzugeben
Delphi-Quellcode:
IniF.WriteEnum<TIniSettings, TModes>(...)
. Wann der Compiler das auch ohne die Angabe hinkriegt, habe ich auch noch nicht so richtig rausgefunden.

a.def 16. Apr 2017 14:30

AW: Codezeile in Funktion umwandeln mit Schwierigkeiten
 
Zitat:

Es ist in der Regel auch notwendig die Typen beim Aufruf anzugeben
Das ist eine gute Information. Werde ich mich dran halten. Ich habe eben einfach wie wild T und T2 hin und her getauscht und so weiter und so herausbekommen, wie was funktioniert und was wofür zuständig ist. Try and Error :thumb:

Danke für deine Hilfe und dafür, dass ich was neues gelernt habe.


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