Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Prüfen und Casten auf einen Rutsch (https://www.delphipraxis.net/169425-pruefen-und-casten-auf-einen-rutsch.html)

sx2008 18. Jul 2012 21:05

Delphi-Version: 5

Prüfen und Casten auf einen Rutsch
 
Bin gerade aus Zufall auf folgende Idee gekommen, dass man die Prüfung mit is und eine anschliesende Cast-Operation zusammenfassen könnte:
Delphi-Quellcode:
function IsKindOf(obj:TObject; AClass:TClass; var x):Boolean;
begin
  Result := obj is AClass;
  if Result then
    TObject(x) := obj
  else
    TObject(x) := nil;
end;

// Mit Hilfsfunktion
procedure TForm1.Button1Click(Sender: TObject);
var
  b : TButton;
begin
  if IsKindOf(Sender, TButton, b) then
    b.Caption := 'ich bin ein Button';
end;

// Ohne Hilfsfunktion
procedure TForm1.Button1Click(Sender: TObject);
var
  b : TButton;
begin
  if Sender is TButton then
  begin
    b := TButton(Sender);
    b.Caption := 'ich bin ein Button';
  end;
end;
Falls das jemand gut findet, darf er die Funktion behalten.

s.h.a.r.k 18. Jul 2012 21:24

AW: Prüfen und Casten auf einen Rutsch
 
Ist Delphi 5 wirklich zwingend, oder hast du das nur als minimal Version angegeben?

Denn ansonsten würde ich das über einen Class Helper erledigen:
Delphi-Quellcode:
TObjectHelper = class helper(TObject)
public
  function TryCast<TCastType>(out Object: TCastType): Boolean;
end;


function TObjectHelper.TryCast<TCastType>(out Object: TCastType): Boolean;
begin
  Result := Self is AClass;
  if Result then
    Object := Self
  else
    Object := nil;
end;
Ich hoffe, der Code ist korrekt... Ist gerade einfach mal schnell aus dem Kopf runter geschrieben...

himitsu 18. Jul 2012 21:54

AW: Prüfen und Casten auf einen Rutsch
 
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  Button: TButton absolute Sender;
begin
  if Sender is TButton then
    Button.Caption := 'ich bin ein Button';
end;

Bei solchen Funktionen kenn ich es oft, daß sie den Ausgabewert nur setzen, wenn die Prüfung erfolgreich war.
Delphi-Quellcode:
function TObjectHelper.TryCast<TCastType>(out Object: TCastType): Boolean;
begin
  Result := Self is AClass;
  if Result then
    Object := Self;
end;
Aber ich glaub es könnte fehlerunanfälliger sein, wenn man den Wert dennoch initialisiert (nil).

s.h.a.r.k 18. Jul 2012 22:03

AW: Prüfen und Casten auf einen Rutsch
 
Nachdem es eh ein out-Parameter ist und man nach einem False-Rückgabewert eh tunlichst nicht darauf zugreifen sollte, ists eigentlich egal. Die Frage ist nur, was ist gute Praxis?! ;)

Uwe Raabe 18. Jul 2012 23:04

AW: Prüfen und Casten auf einen Rutsch
 
Kleine Korrektur:

Delphi-Quellcode:
function TObjectHelper.TryCast<TCastType: Class>(out Instance: TCastType): Boolean;
begin
  Result := Self is TCastType;
  if Result then
    Instance:= Self
  else
    Instance:= nil;
end;
Allerdings könnte ein public sichtbarer
Delphi-Quellcode:
helper for TObject
das ganze übrige Helper Szenario obsolet machen.

Besser wäre vielleicht ein Record:

Delphi-Quellcode:
type
  TCaster = record
    function TryCast<TCastType: Class>(Source: TObject; out Target: TCastType): Boolean;
  end;

function TCaster.TryCast<TCastType>(Source: TObject; out Target: TCastType): Boolean;
begin
  Result := Source is TCastType;
  if Result then
    Target := Source
  else
    Target := nil;
end;

bernau 19. Jul 2012 00:55

AW: Prüfen und Casten auf einen Rutsch
 
Nennt mich altmodisch, aber was ist gegen eine "einfache" Funktion, wie sx2008 es gezeigt hat, auszusetzen.

Was ist der Vorteil von Class-Helper. In den Beiträgen sehe ich zwar, wie der Classhelper definiert ist. Aber wie wird er angewendet?

Sir Rufo 19. Jul 2012 01:03

AW: Prüfen und Casten auf einen Rutsch
 
Ein ClassHelper erweitert eine Klasse um Methoden, die dann einfach benutzt werden können.
In diesem Beispiel also so
Delphi-Quellcode:
if Sender.TryCast<TEdit>( Edit ) then
  Edit.Text := 'tut';

bernau 19. Jul 2012 01:34

AW: Prüfen und Casten auf einen Rutsch
 
Zitat:

Zitat von Sir Rufo (Beitrag 1175147)
Ein ClassHelper erweitert eine Klasse um Methoden, die dann einfach benutzt werden können.
In diesem Beispiel also so
Delphi-Quellcode:
if Sender.TryCast<TEdit>( Edit ) then
  Edit.Text := 'tut';

Danke. Wieder was gelernt.

uligerhardt 19. Jul 2012 07:14

AW: Prüfen und Casten auf einen Rutsch
 
Zitat:

Zitat von bernau (Beitrag 1175146)
Nennt mich altmodisch, aber was ist gegen eine "einfache" Funktion, wie sx2008 es gezeigt hat, auszusetzen.

Das einzige, was mich stört, ist die fehlende Typsicherheit (siehe Parameter
Delphi-Quellcode:
var x
).

uligerhardt 19. Jul 2012 07:19

AW: Prüfen und Casten auf einen Rutsch
 
Zitat:

Zitat von Sir Rufo (Beitrag 1175147)
Ein ClassHelper erweitert eine Klasse um Methoden, die dann einfach benutzt werden können.
In diesem Beispiel also so
Delphi-Quellcode:
if Sender.TryCast<TEdit>( Edit ) then
  Edit.Text := 'tut';

Delphi-Quellcode:
if TryCast<TEdit>(Sender, Edit) then
  Edit.Text := 'tut';
wäre aber auch OK und käme ohne class helper aus. Leider kann Delphi (noch) keine globalen generischen Routinen. (Warum eigentlich?)

himitsu 19. Jul 2012 07:57

AW: Prüfen und Casten auf einen Rutsch
 
Zitat:

Zitat von uligerhardt (Beitrag 1175160)
Delphi-Quellcode:
if TryCast<TEdit>(Sender, Edit) then
  Edit.Text := 'tut';
Leider kann Delphi (noch) keine globalen generischen Routinen. (Warum eigentlich?)

Das wüste ich auch gerne, dazumal ich sogar mal eine "Lösung" genannt hatte, wie man es dennoch umgehn könnte.
Einfach eine implizite Klasse drum, um die Funktion, und schon ginge es ohne große Änderung des Compilers.

Nja, aber wenn du OOP mit arbeitest, und diese "Funktion innerhalb von Methoden verwendest, dann kannst du immernoch den ClassHelper verwenden.
Und im Notfall kombiniert man einfach Beides.
Delphi-Quellcode:
  TCastHelper = class helper for TObject
    class function TryCast<TCastType: Class>(Source: TObject; out Target: TCastType): Boolean; overload;
    function TryCast<TCastType: Class>(out Target: TCastType): Boolean; overload;
  end;
Delphi-Quellcode:
// z.B. im ButtonClick:
if x.TryCast(y) or TryCast(x, y) then

Uwe Raabe 19. Jul 2012 11:46

AW: Prüfen und Casten auf einen Rutsch
 
Zitat:

Zitat von himitsu (Beitrag 1175163)
Zitat:

Zitat von uligerhardt (Beitrag 1175160)
Leider kann Delphi (noch) keine globalen generischen Routinen. (Warum eigentlich?)

Das wüste ich auch gerne, dazumal ich sogar mal eine "Lösung" genannt hatte, wie man es dennoch umgehn könnte.
Einfach eine implizite Klasse drum, um die Funktion, und schon ginge es ohne große Änderung des Compilers.

Globale Prozeduren und Funktionen sind ja sowas von out 8-) - man nimmt dafür jetzt statische Klassenmethoden in Records.

himitsu 19. Jul 2012 11:49

AW: Prüfen und Casten auf einen Rutsch
 
Ja, ich hab mir z.B. ein generisches IfThen gebastelt (z.B. für Enums und Klassen) und weißt du wie blöd das
Delphi-Quellcode:
TGenerics.IfThen<TIrgendwas>(...)
aussieht?
Ich hätte es da lieber als überladene Prozedur zu den anderen existierenden IfThen's gehabt. :cry:


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