So, da Einige mit den Interfaces als Callback nicht klar kommen (es ihnen zu umständlich ist),
mal eine Frage, was man nun am Besten machen könnte.
- alles so lassen, wie es ist (nur IDECProgress)
nur mag es niemand -> https://www.delphipraxis.net/206384-...ml#post1479406
- das mit dem Interface lassen, aber das dafür bissl verändern (nur IDECProgress2)
- das Originale Interface hat den Nachteil, dass man den Anfang und vorallem das Ende nicht sicher erkennen kann
- zusätlich einen Methoden-Callback implementieren (alles Mögliche reinmachen)
- überall bei jedem Verwender die Überladung für jeden CallbackType -> https://github.com/geheimniswelten/D...p/IDECProgress
- eine manuelle Überladung mit einem WrapperObjekt (die Verwender nehmen immer nur das Interface)
- vielleicht kennt doch noch jemand eine Möglichkeit für einen impliziten Cast
- das Interface durch eine Methode ersetzen (nur TDECProgress2), also weiterhin nur Einwas)
- oder irgendwas Anderes ...
Es darf auch gern jemand zu den Bezeichnern (Methodennamen) seinen Senf zu eben, da ich das Gefühl hab, das geht bestimmt viel besser. (IDECProgress
2)
----------
So ist es aktuell
Delphi-Quellcode:
type
// das war Einigen zu schwer verständlich zu verstehen
{IDECProgress = interface
procedure Progress(const Min, Max, Pos: Int64);
end;}
// aber umbenannt und mit Kommentar ist es nicht wirklich besser geworden
IDECProgress = interface
/// <summary>...
procedure OnProgress(const Min, Max, Pos: Int64);
end;
IDECHash = interface
...
/// <summary>...
procedure CalcStream(const Stream: TStream; Size: Int64; var HashResult: TBytes;
const OnProgress: IDECProgress = nil);
...
end;
procedure TMyClass.OnProgress(const Min, Max, Pos: Int64);
begin
ProgressBar.Min := Min; // 0;
ProgressBar.Max := Max; // 100;
ProgressBar.Position := Pos; // (Pos - Min) * 100 div (Max - Min);
end;
Dieses nun mit einer zusätzlichen EventMethode überladen
und weiter zusätzlich noch ein "optimaleres" Interface.
Es gibt es an sehr vielen Stellen nun die einbindenen Methoden somit unschön doppelt/dreifach,
wenn man das Alte aus Kompatibilitätsgründen beibehalten möchte, außerdem hat ein Interface auch seine Vorteile.
Delphi-Quellcode:
// siehe https://github.com/geheimniswelten/DelphiEncryptionCompendium/compare/development...geheimniswelten:develop/IDECProgress
// funktioniert, aber an vielen Stellen "unschön" mehrfache Implementation, für jeden Callback-Type
{$IFDEF FPC}
// ich weiß noch nicht ob/wie das mit den Anonymen im Lazarus/FPC geht
TDECProgress = procedure(Sender: TObject; const Min, Max, Pos: Int64) of object;
{$ELSE}
TDECProgress = reference to procedure(Sender: TObject; const Min, Max, Pos: Int64);
{$ENDIF}
IDECProgress = interface
procedure OnProgress(const Min, Max, Pos: Int64);
end;
IDECProgress2 = interface
procedure OnProgressStart(const Min, Max: Int64);
procedure OnProgress(const Pos: Int64 {; Percent: Single});
procedure OnProgressStop(const Pos: Int64 {; Percent: Single});
procedure OnProgressError(const Pos: Int64 {; Percent: Single}; const ErrorText: string);
end;
IDECHash = Interface
...
/// <summary>...
procedure CalcStream(const Stream: TStream; Size: Int64; var HashResult: TBytes;
const OnProgress: IDECProgress2 = nil); overload;
procedure CalcStream(const Stream: TStream; Size: Int64; var HashResult: TBytes;
const OnProgress: IDECProgress); overload;
procedure CalcStream(const Stream: TStream; Size: Int64; var HashResult: TBytes;
const OnProgress: TDECProgress); overload;
...
end;
procedure TMyClass.OnProgressStart(const Min, Max: Int64);
begin
ProgressBar.Min := Min;
ProgressBar.Max := Max;
ProgressBar.State := pbsNormal;
ProgressBar.Position := 0;
StatusLabel.Visible := False;
end;
procedure TMyClass.OnProgress(const Pos: Int64);
begin
ProgressBar.Position := Pos;
end;
procedure TMyClass.OnProgressStop(const Pos: Int64);
begin
ProgressBar.Position := Pos;
ProgressBar.State := pbsPaused;
end;
procedure TMyClass.OnProgressError(const Pos: Int64; const ErrorText: string);
begin
ProgressBar.Position := Pos;
ProgressBar.State := pbsError;
StatusLabel.Caption := ErrorText;
StatusLabel.Visible := True;
end;
Vererbung würde das Ausmaß minimieren, aber eine Vererbung ist hier nicht "sinnvoll" möglich
und an vielen Stellen ist es weiterhin doppelt (Methode+Interface), auch wenn beide Interfaces nun im selben Parameter-Vorfahren übergeben werden könnten.
Delphi-Quellcode:
// ist keine Lösung
type
IDECProgress = interface
procedure OnProgress(const Min, Max, Pos: Int64);
end;
IDECProgress2 = interface(IDECProgress)
{weiterhin ist das das alte OnProgress vorhanden
procedure OnProgress(const Min, Max, Pos: Int64); }
procedure OnProgressStart(const Min, Max: Int64);
procedure OnProgress(const Pos: Int64 {; Percent: Single}); overload;
procedure OnProgressStop(const Pos: Int64 {; Percent: Single});
procedure OnProgressError(const Pos: Int64 {; Percent: Single}; const ErrorText: string);
end;
Die Verwebung zu verschieben wird bestimmt auch niemand verstehen,
also mit einem IDECProgressBase oder gar direkt IInterface als Parameter.
Und ins letzte Interface passen die Methoden des Originals nicht rein, bzw. ich würde den doppelten OnProgress-Aufruf unschön finden.
Delphi-Quellcode:
// unverständliche mögliche Lösung
type
IDECProgressBase = interface
// ohne was drin
end;
IDECProgress = interface(IDECProgressBase)
procedure OnProgress(const Min, Max, Pos: Int64);
end;
IDECProgress2 = interface(IDECProgressBase)
{weiterhin ist das das alte OnProgress vorhanden
procedure OnProgress(const Min, Max, Pos: Int64); }
procedure OnProgressStart(const Min, Max: Int64);
procedure OnProgress(const Pos: Int64 {; Percent: Single}); overload;
procedure OnProgressStop(const Pos: Int64 {; Percent: Single});
procedure OnProgressError(const Pos: Int64 {; Percent: Single}; const ErrorText: string);
end;
Statt der vielen Überladungen könnte man auch nur das größte Interface (IDECProgress2) implementieren
und einen "manuellen" Wapper bauen, aber das versteht scheinbar auch niemand, bzw. es ist zu umständlich.
https://www.delphipraxis.net/206384-...ml#post1479406
Allerdings ist das von den "möglichen" Implementierung her eigentlich die schönste/schlankeste Variante,
auch wenn man bei Übergabe einer Callback-Methode, oder des kleinen Interfaces, einen manuellen Cast einfügen muß.
Delphi-Quellcode:
// funktioniert und kompakt (aber findet bzw. versteht vielleicht niemand)
type
TDECProgressWrapper = class(TInterfacedObject, IDECProgress2)
private
...
public
class function Create(Sender: TObject; Intf: IDECProgress): IDECProgress2; overload;
class function Create(Sender: TObject; Proc: TDECProgress): IDECProgress2; overload;
end;
Hash := DECHash.CalcStream(Stream, Size, TDECProgressWrapper.Create(OnProgressMethodOrIDECProgress));
Als Record-Helper mit Implicit-Class-Operator an dem Interface,
das funktioniert leider nicht.
Delphi-Quellcode:
// compiliert leider (noch) nicht
type
// [dcc32 Fehler] E2474 Record-Typ erforderlich
TDECProgressHelper = record helper for IDECProgress2
class operator Implicit(Value: IDECProgress): IDECProgress2;
class operator Implicit(Value: TDECProgress): IDECProgress2;
end;
// [dcc32 Fehler] E2021 Klassentyp erwartet
TDECProgressHelper = class helper for IDesignerHook
class operator Implicit(Value: IDECProgress): IDECProgress2;
class operator Implicit(Value: TDECProgress): IDECProgress2;
end;
// aber per se kann man scheinbar doch Casts nachträglich anhängen (der Compiler meckert nicht)
TIntegerHelper = record helper for Integer
class operator Implicit(Value: Byte): Integer;
end;
TPointHelper = record helper for TPoint
class operator Implicit(Value: TRect): TPoint;
end;
Aber geil wäre es schon, wenn die Überladungen nur an einer Stelle liegen würden, wie auch beim Wrapper,
anstatt
überall bei jeder Verwendung als
overload einbauen zu müssen.
Umsetzung siehe
https://github.com/geheimniswelten/D...p/IDECProgress
-----
Falls noch jemand andere Lösungen kennt ... bitte immer her damit.
Ansonsten fällt mir nur noch eine radikale "übersichtliche" Lösunge ein,
also das Interface komplett zu löschen und durch eine Event-Methode zu ersetzen.