Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   generischen Typen als "irgendeinen" String-Typen deklarieren (https://www.delphipraxis.net/154472-generischen-typen-als-irgendeinen-string-typen-deklarieren.html)

himitsu 12. Sep 2010 12:24

Delphi-Version: 2010

generischen Typen als "irgendeinen" String-Typen deklarieren
 
Delphi-Quellcode:
type
  TMyClass = class
    procedure Test<typ>(S: typ);
  end;

procedure TMyClass.Test<typ>(S: typ);
var S2: String;
begin
  S2 := S; <<<
end;
Zitat:

[DCC Fehler] Unit4.pas(32): E2010 Inkompatible Typen: 'string' und 'typ'
Wie kann ich jetzt innerhalv der Klasse den "typ" kompatibel zu String bekommen?
Man kann zwar z.B. so
Delphi-Quellcode:
procedure Test<typ: class>(S: typ);
sagen, daß es irgendeine Klasse sein wird,
aber wie kann man es zum String kompatibel machen?
(AnsiString, RawByteString, UnicodeString, String)

Ich wollte die Generics benutzen, um einige "ähnliche" Funktionen zu kombinieren.
Wobei sich dort nur ein paar Parameter so unterscheiden, daß sie einmal ANSI und dann auch mal als Unicode vorhanden sein können.

Da es einige Funktionen mit bis zu 3 String-Parametern gibt und ich absolut nicht die automatischen Stringumwandlungen, seitens Delphi, gebrauchen kann, gibt es da also öfters mal bis zu 3^3 = 9 Funktionen, welche alle fast den selben Inhalt besitzen.

USchuster 12. Sep 2010 14:42

AW: generischen Typen als "irgendeinen" String-Typen deklarieren
 
Die Vereinfachung, welche Du mit Generics erreichen möchtest, funktioniert leider nicht aufgrund des nicht vorhandenen Typsystems bzw. der nicht vorhandener Contraints für Stringtypen. Um die Verwendung von überladenen Methoden wirst Du leider nicht drumherum kommen.

Theoretisch könntest Du es analog zu folgendem Beispiel implementieren:
Delphi-Quellcode:
program ParameterizedStringMethodTest;

{$APPTYPE CONSOLE}

type
  TMyClass = class
    class procedure Test<T>(S: T);
  end;

  T1252String = type AnsiString(1252);

class procedure TMyClass.Test<T>(S: T);
var
  StringTypeInfo: Pointer;
begin
  StringTypeInfo := TypeInfo(T);
  if StringTypeInfo = TypeInfo(AnsiString) then
    WriteLn('AnsiString: ' + AnsiString(Pointer(@S)^))
  else
  if StringTypeInfo = TypeInfo(RawByteString) then
    WriteLn('RawByteString: ' + RawByteString(Pointer(@S)^))
  else
  if StringTypeInfo = TypeInfo(UnicodeString) then
    WriteLn('UnicodeString: ' + UnicodeString(Pointer(@S)^))
  else
  if StringTypeInfo = TypeInfo(ShortString) then
    WriteLn('ShortString: ' + ShortString(Pointer(@S)^))
  else
  if StringTypeInfo = TypeInfo(UTF8String) then
    WriteLn('UTF8String: ' + UTF8String(Pointer(@S)^))
  else
  if StringTypeInfo = TypeInfo(T1252String) then
    WriteLn('T1252String: ' + T1252String(Pointer(@S)^))
  else
    WriteLn('Unknown type');
end;

begin
  TMyClass.Test(AnsiString('Ansi'));
  TMyClass.Test(RawByteString('Raw'));
  TMyClass.Test(UnicodeString('Uni'));
  TMyClass.Test(string('string is Uni too'));
  TMyClass.Test(ShortString('Short'));
  TMyClass.Test(UTF8String('UTF8'));
  TMyClass.Test(T1252String('1252'));
  ReadLn;
end.
Der Output müsste so aussehen:
Code:
AnsiString: Ansi
RawByteString: Raw
UnicodeString: Uni
UnicodeString: string is Uni too
ShortString: Short
UTF8String: UTF8
T1252String: 1252

HeZa 12. Sep 2010 19:43

AW: generischen Typen als "irgendeinen" String-Typen deklarieren
 
Zitat:

Zitat von himitsu (Beitrag 1049004)
Wie kann ich jetzt innerhalv der Klasse den "typ" kompatibel zu String bekommen?

Der spontane Gedanke (so ohne groß nachzudenken oder gar zu testen): Verwende ToString von TObject

himitsu 12. Sep 2010 20:51

AW: generischen Typen als "irgendeinen" String-Typen deklarieren
 
Ich habe aber Strings und keine Objekte.

Aktuell umgeh ich den Compiler über wilde Pointervergewaltigungen und blöde IF-Kontrukte, wobei mir {$IF lieber wäre :cry:



Es wäre schön, wenn es wirklich endlich mal einen zweifasigen Compiler gäbe und dieser erst die Typenprüfungen macht, wenn er einen Typen übergeben bekommt.

Uwe Raabe 12. Sep 2010 21:13

AW: generischen Typen als "irgendeinen" String-Typen deklarieren
 
Zitat:

Zitat von himitsu (Beitrag 1049144)
Es wäre schön, wenn es wirklich endlich mal einen zweifasigen Compiler gäbe und dieser erst die Tüpenprüfungen macht, wenn er einen Typen übergeben bekommt.

Er hat Jehova gesagt :shock:

ConstantGardener 13. Sep 2010 06:32

AW: generischen Typen als "irgendeinen" String-Typen deklarieren
 
@Uwe :thumb:

[ot]

...ist hier etwa Weibsvolk anwesend ?

Ps. Ich liebe diesen Film!

himitsu 13. Sep 2010 16:45

AW: generischen Typen als "irgendeinen" String-Typen deklarieren
 
So, fast alle Arbeit umsonst.

Mein Fazit:
Für eine gleichzeitige Ansi/Unicode-Programmierung ist diese besch** Generic-Implementierung absolut nicht zu gebrauchen.

Danke Emba, für eure tolle Arbeit.

mkinzler 13. Sep 2010 17:37

AW: generischen Typen als "irgendeinen" String-Typen deklarieren
 
Dazu ist sie eigentlich auch nicht gedacht

Stevie 13. Sep 2010 18:31

AW: generischen Typen als "irgendeinen" String-Typen deklarieren
 
Mal ehrlich, vergiss den ganzen AnsiKrams und benutz string und fertig. Wer dennoch was nicht Unicode kompatibles haben will solls halt erst in string umcasten und in deine Methoden reingeben.

himitsu 13. Sep 2010 18:47

AW: generischen Typen als "irgendeinen" String-Typen deklarieren
 
Das ist eine Bibliothek, welche mit Ansi, UTF-8 und Co. umgehen können muß.
Da gibt es keinen anderen Weg.

Wenn ich dieses nur als "String" (Unicode) auslege, dann müssen "extern" Stringumwandlungen vorgenommen werden und das erzeugt zusätzliche Fehlerquellen.
Es gibt schon seine Grüne, warum ich seit Monaten versuche hierfür eine Ansi/Unicode-kompatible Schittstelle hinzubekommen.

Über die Generics hatte ich mir hier (intern) ein paar Vereinfachungen erhofft, in Form von knapp 1000-2000 Zeilen Quellcode, aka knapp 1/4 bis 1/3 eingesparten "doppelten" Code.
Nja, knapp 2-3 Tage umsonst dahingegangen, wärend ich versuchte die Generics passend hinzubiegen und dann scheiterte es an Compilerfehlern.

jbg 13. Sep 2010 18:54

AW: generischen Typen als "irgendeinen" String-Typen deklarieren
 
Zitat:

Zitat von himitsu (Beitrag 1049337)
Für eine gleichzeitige Ansi/Unicode-Programmierung ist diese besch** Generic-Implementierung absolut nicht zu gebrauchen.

Das liegt vielleicht daran, dass für dein Vorhaben Templates notwendig sind und Delphi hat diese nicht. Delphi hat hier nur Generics im Angebot (die auch noch ein paar Bugs haben). Bei C# hättest du die selben Probleme (bis auf dass String dort ein object ist und somit über ToSring() verfügt, aber im Endeffekt würdest du dort dann auch wieder alles nach Unicode-String konvertieren, damit arbeiten und zurückschreiben).
Generics sind nun mal keine C++Templates.

Stevie 13. Sep 2010 18:58

AW: generischen Typen als "irgendeinen" String-Typen deklarieren
 
Type constraints kannst du in Delphi nur auf Interfaces oder Klassen angeben (glaub zusätzlich noch den "Muss constructor besitzen" Constraint, sonst fällt mir keiner ein) sonst nix. Das geht (wenn überhaupt, ich mach nicht viel damit) in .Net nur, weil alles ein object ist.

Mach entweder 2 oder mehrere Klassen aus dem Teil, welche ganz klar die Stringtypen abgrenzen oder schmeiß bestimmte davon ganz raus. Generics sind kein Werkzeug um mal eben zwei verschiedene Sachen (auch wenn sie ähnlich sind) in eins zu quetschen.

@Andreas: Es könnte möglich sein, die Technik, die man schon vor den Generics für eine typensichere TObjektList nutzen konnte, auch dafür zu nutzen, das funktionierte auch über sowas wie nen Template, aber genau weiß ichs auch nicht. (Quelle)

himitsu 13. Sep 2010 19:07

AW: generischen Typen als "irgendeinen" String-Typen deklarieren
 
Nja, im Prinzip kann man nur Records und Objekte "verwenden",

wobei man innerhalb der generischen Klasse/Funktion nur mit Instanzen jonglieren kann, aber nicht mir Funktionen davon oder dessen Inhalt.

Wenn der Delphicompiler aber den generischen Typ erst "auswerten" würde und vorher nur die Syntax prüfen täte, dann könnte man viel mehr damit anstellen. :cry:

Stevie 13. Sep 2010 19:10

AW: generischen Typen als "irgendeinen" String-Typen deklarieren
 
Zitat:

Zitat von himitsu (Beitrag 1049365)
Nja, im Prinzip kann man nur Records und Objekte "verwenden",

wobei man innerhalb der generischen Klasse/Funktion nur mit Instanzen jonglieren kann, aber nicht mir Funktionen davon oder dessen Inhalt.

Wenn der Delphicompiler aber den generischen Typ erst "auswerten" würde und vorher nur die Syntax prüfen täte, dann könnte man viel mehr damit anstellen. :cry:

Das stimmt nicht. Sofern du einen Constraint setzt, kannst du innerhalb der Methoden deiner Klasse problemlos auf Eigenschaften und Methoden des generischen Typs zugreifen, du musst nur unter Umständen T auf deine Klasse/Interface umcasten.

Beispiel:
Delphi-Quellcode:
type
  TFoo<T: class, constructor> = class
    function CreateNewObject: T;
    procedure FreeAndNil(var AObject: T);
    function GetClassName: string;
  end;

{ TFoo<T> }

function TFoo<T>.CreateNewObject: T;
begin
  Result := T.Create;
end;

procedure TFoo<T>.FreeAndNil(var AObject: T);
begin
  AObject.Free;
  AObject := nil;
end;

function TFoo<T>.GetClassName: string;
begin
  Result := T.ClassName;
end;

himitsu 13. Sep 2010 19:58

AW: generischen Typen als "irgendeinen" String-Typen deklarieren
 
geht nicht
Delphi-Quellcode:
type
  TFoo<T: class, constructor> = class
    procedure DoTest;
  end;

procedure TFoo<T>.DoTest;
begin
  T.Test;
end;
Statt class, constructor oder record wäre es schöner, wenn man auch direkt Typen angeben könnte,
bzw. wenn der Code erstmal nur auf korrekte Syntag geprüft und erst bei Nutzung, mit dem "Zieltyp" weiter geprüft würde.

Stevie 13. Sep 2010 21:06

AW: generischen Typen als "irgendeinen" String-Typen deklarieren
 
Zitat:

Zitat von himitsu (Beitrag 1049379)
geht nicht
Delphi-Quellcode:
type
  TFoo<T: class, constructor> = class
    procedure DoTest;
  end;

procedure TFoo<T>.DoTest;
begin
  T.Test;
end;
Statt class, constructor oder record wäre es schöner, wenn man auch direkt Typen angeben könnte,
bzw. wenn der Code erstmal nur auf korrekte Syntag geprüft und erst bei Nutzung, mit dem "Zieltyp" weiter geprüft würde.

Und seit wann hat TObject ne Methode namens Test?
Delphi-Quellcode:
type
  TFoo = class
    procedure Test;
  end;

  TFoo2<T: TFoo> = class
    procedure DoTest;
  end;

procedure TFoo2<T>.DoTest;
begin
  T.Test;
end;

procedure TFoo.Test;
begin

end;
In dem Beispiel rufst du übrigens eine Methode auf eine Klasse auf, nur dass ich das erwähnt habe...

Kann es sein, dass du das mit den Generics noch nicht ganz verstanden hast?

himitsu 13. Sep 2010 21:13

AW: generischen Typen als "irgendeinen" String-Typen deklarieren
 
Das sage ich ja "man kann auf keine Eigenschaften und Methoden eines generischen Typs zugreifen".

Stevie 13. Sep 2010 21:20

AW: generischen Typen als "irgendeinen" String-Typen deklarieren
 
Zitat:

Zitat von himitsu (Beitrag 1049398)
Das sage ich ja "man kann auf keine Eigenschaften und Methoden eines generischen Typs zugreifen".

Logisch, wenn du keine Instanz davon hast, oder?
Delphi-Quellcode:
type
  TFoo = class
  private
    FCaption: string;
  public
    procedure Bar;
    property Caption: string read FCaption write FCaption;
  end;

  TFooContainer<T: TFoo> = class
    procedure DoSomething(x: T);
  end;

procedure TFooContainer<T>.DoSomething(x: T);
begin
  x.Caption := 'Hello Himi';
  x.Bar();
end;

procedure TFoo.Bar;
begin
  ShowMessage(FCaption);
end;

var
  foo: TFoo;
begin
  foo := TFoo.Create;
  with TFooContainer<TFoo>.Create do
  begin
    DoSomething(foo);
    Free;
  end;
  foo.Free;
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 12:07 Uhr.

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