Einzelnen Beitrag anzeigen

Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#1

Generics: Instanz-Erzeugung in generischer Klasse

  Alt 9. Okt 2011, 21:03
Ich habe hier eine generische Klassen/Interface Definition, die von TComponent abgeleitet ist.

Wie bekomme ich die Klasse jetzt dazu eine passende Instanz zu erzeugen?
TGenClass<T:Class, Constructor> = class sagt ja nur aus, dass die Klasse T einen parameterlosen Constructor hat.
TComponent hat aber einen Constructor mit Parameter (obwohl ich dem ledigleich ein schnödes nil mitgeben würde).
Das T.Create; findet der Compiler gut, aber es ist nicht so wie ich das möchte, denn
Delphi-Quellcode:
var
  MyButton : IGenericLink<TButton>;
begin
  MyButton := TGenericLink<TButton>.Create;
  MyButton.Link.OnClick := ButtonClick; // hier rummst es, und das soll es nicht
end;
und T.Create(nil); findet der Compiler total blöde

Sinn und Zweck dieser Übung ist das Binding von Komponenten einer Form zu einer Controller-Unit.
Dabei soll es die Controller-Unit aushalten, wenn auf der Form nicht alle Komponenten vorhanden sind. (Darum hält TGenericLink eben ein Dummy-Object vor, auf das zugegriffen wird, wenn kein gültiger Link gebildet werden konnte).

Wer kann mir da mal auf den lahmen Gaul helfen?

Die ganze Unit mal zum überfliegen:
Delphi-Quellcode:
unit FormBinding;

interface

uses
  Classes;

type
  IGenericLink<T: TComponent, Constructor> = interface
    ['{7650F483-5FDD-431F-96D1-65536B127BB5}']
    function GetLink: T;
    procedure SetLink(const Value: T);
    property Link: T read GetLink write SetLink;
    procedure LinkTo(const Value: TComponent); overload;
    procedure LinkTo(const Owner: TComponent;
      const ComponentName: string); overload;
    function IsLinked: Boolean;
    function GetOnLinkChanged: TNotifyEvent;
    procedure SetOnLinkChanged(const Value: TNotifyEvent);
    property OnLinkChanged: TNotifyEvent read GetOnLinkChanged
      write SetOnLinkChanged;
  end;

  TGenericLink<T: TComponent, Constructor> = class(TInterfacedObject,
    IGenericLink<T>)
  private
    fInt: T;
    fExt: T;
    fOnLinkChanged: TNotifyEvent;
    function GetLink: T;
    procedure SetLink(const Value: T);
    function GetOnLinkChanged: TNotifyEvent;
    procedure SetOnLinkChanged(const Value: TNotifyEvent);
  public
    constructor Create;
    destructor Destroy; override;
    property Link: T read GetLink write SetLink;
    procedure LinkTo(const Value: TComponent); overload;
    procedure LinkTo(const Owner: TComponent;
      const ComponentName: string); overload;
    function IsLinked: Boolean;
    property OnLinkChanged: TNotifyEvent read GetOnLinkChanged
      write SetOnLinkChanged;
  end;

implementation

{ TGenericLink<T> }

constructor TGenericLink<T>.Create;
begin
  inherited Create;
  fInt := T.Create; // <<-- ???
end;

destructor TGenericLink<T>.Destroy;
begin
  fInt.Free;
  inherited;
end;

function TGenericLink<T>.GetLink: T;
begin
  if Assigned(fExt) then
    Result := fExt
  else
    Result := fInt;
end;

function TGenericLink<T>.GetOnLinkChanged: TNotifyEvent;
begin
  Result := fOnLinkChanged;
end;

function TGenericLink<T>.IsLinked: Boolean;
begin
  Result := Assigned(fExt);
end;

procedure TGenericLink<T>.LinkTo(const Owner: TComponent;
  const ComponentName: string);
begin
  LinkTo(Owner.FindComponent(ComponentName));
end;

procedure TGenericLink<T>.LinkTo(const Value: TComponent);
begin
  if Assigned(Value) and Value.InheritsFrom(T) then
    SetLink(Value)
  else
    SetLink(nil);
end;

procedure TGenericLink<T>.SetLink(const Value: T);
begin
  fExt := Value;
  if Assigned(OnLinkChanged) then
    OnLinkChanged(Self);
end;

procedure TGenericLink<T>.SetOnLinkChanged(const Value: TNotifyEvent);
begin
  fOnLinkChanged := Value;
end;

end.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)

Geändert von Sir Rufo ( 9. Okt 2011 um 21:07 Uhr)
  Mit Zitat antworten Zitat