2016-05-24 13 views
2

Ist es möglich, einen generischen Parameter zu haben, um die Schnittstelle zu definieren, die eine Klasse implementiert?
Oder hat jemand eine Erklärung, warum Delphi dies nicht zulässt (Oder mache ich es einfach falsch?):Generischer Parameter zum Definieren der Schnittstelle, die die generische Klasse implementiert

TInterfacedMyWrapper<T: IInterface> = class(TMyWrapper, T) 
    function PropGetIntf(): T; 
    property Intf: T read PropGetIntf implements T; 
end; 

Das folgende Fehler ergibt:

  • E2205: Interface type required
  • E2259: Implements clause only allowed for properties of class or interface type

Dies ist meine Abhilfe:

TInterfacedMyWrapper<T: IInterface> = class(TMyWrapper) 
    function PropGetIntf(): T; 
    property Intf: T read PropGetIntf; 
end; 

TIFooMyWrapper = class(TInterfacedMyWrapper<IFoo>, IFoo) 
    property Intf: IFoo read PropGetIntf implements IFoo; 
end; 

Aber das zwingt mich, eine separate Klasse für jede Schnittstelle zu definieren. I'ld mag eher schreiben:

TInterfacedMyWrapper<IFoo>.Create(CompToWrap); 



Herausgegeben (etwas mehr Kontext, meine Ziele zu erklären - ich hoffe, es ist nicht zu verwirrend ...):

ich mehrere Klassen abgeleitet von TFooComp, die nicht geändert werden kann. Und ich habe eine Wrapper-Klasse TMyWrapper, die von TBarBase erbt. Ich kann TBarBase nicht ändern. TMyWrapper ist ein Wrapper für TFooComp (Art von Adaptermuster).

Jede TFooComp-abgeleitete Klasse kann eine Schnittstelle freilegen. Was ich erreichen möchte, ist, dass TInterfacedMyWrapper diese Schnittstelle ebenfalls offen legt (und an die wrapped TFooComp delegiert).

Dies funktioniert irgendwie:

constructor TMyWrapper.CreateNew(AOwner: TComponent; FooClass: TFooClass); 
begin 
    FWrappedFooComp := FooClass.Create(Self); 
    //... 
end; 

//... 

function TInterfacedMyWrapper<T>.PropGetIntf(): T; 
begin 
    //see http://stackoverflow.com/questions/4418278/use-of-supports-function-with-generic-interface-type 
    if not Supports(FWrappedFooComp, GetTypeData(TypeInfo(T))^.Guid, Result) then 
     raise Exception.Create('Interface not implemented'); 
end; 

Aber für jede TFooComp abgeleitete Klasse Ich habe eine eigene Wrapper-Klasse erstellen (mit nur einer Erklärung):

TWrappedFooXxx = class(TInterfacedMyWrapper<IXxx>, Ixxx) 
    property Intf: IXxx read PropGetIntf implements IXxx; 
end; 

, dass ich die Verwendung folgender Weg:

Result := TWrappedFooXxx.CreateNew(Owner, TFooXxx); 
Result.DoSomething(); 
(Result as IXxx).DoSomeMore(); 

Die Notwendigkeit, einen eigenen Wrapper zu erstellen c Lass ist, was ich versuche zu vermeiden. Ich würde lieber nur schreiben:

Result := TInterfacedMyWrapper<IXxx>.CreateNew(Owner, TFooXxx); 
Result.DoSomething(); 
(Result as IXxx).DoSomeMore(); 
+0

Ein kleines, aber vollständiges Beispielprogramm wäre besser gewesen, denn dann müssten wir die Typen einiger Dinge nicht erraten (wie "TBarBase" von "TInterfacedObject" erbt oder nicht oder welcher Typ "Ergebnis" in den letzten beiden ist) Schnipsel) –

+0

@StefanGlienke Der echte Code, ist Code, den ich sowieso veröffentlichen wollte. Ich wollte diese Frage nur vor der Veröffentlichung prüfen. Ich habe versucht, diese Frage so zu stellen, dass sie nicht zu eng wird. Aber Sie haben Recht. Ich werde den echten Code aufräumen, ihn veröffentlichen, einen Link zur Verfügung stellen und hier ein Beispielprogramm bereitstellen. (Zu Ihren Fragen: 'TBarBase' und' TMyWrapper' erben von 'TComponent' und implementieren so' IInterface'. Der Typ von 'Result' wird durch den Konstruktor' CreateNew' bestimmt, der von TMyWrapper abgeleitet ist. – yonojoy

Antwort

1

warum Delphi nicht das zulassen?

Da dies keine C++ Vorlagen ist. Der Compiler in Delphi muss die Schnittstellen kennen, die Ihre Klasse implementiert (obwohl es generisch ist). Aber in diesem Fall kann es nicht, weil Sie versuchen, eine noch nicht bekannte Schnittstelle zu implementieren.

+0

OK, das erklärt, warum die Syntax, die ich benutzt habe, nicht funktionieren wird (zwischenzeitlich habe ich versucht, eine "offizielle" Referenz für Ihren Anspruch zu finden, konnte aber keine finden?). Aber die Existenz von 'TVirtualInterface' lässt mich glauben, dass es nicht völlig unmöglich ist, eine Schnittstelle zu implementieren, die der Klasse zur Kompilierungszeit nicht bekannt ist. 'TInterfacedMyWrapper .Create (CompToWrap) als IFoo' wäre auch schön;) – yonojoy

+1

Ich frage mich, was Sie versucht haben zu erreichen, weil' CompToWrap' eindeutig nicht vom Typ 'T' ist, weil Sie dann nirgendwohin kommen, auch wenn es würde mit dem generischen funktionieren, weil Sie die umhüllte Instanz nur einfach in 'PropGetIntf' zurückgeben könnten, aber keinen benutzerdefinierten Code hinzufügen (wie es ein Decorator-Muster tun würde). Bitte geben Sie ein wenig mehr Kontext zu Ihrer Frage –

+0

Ich glaube, er versucht, Interface-Unterstützung dynamisch zu einer Klasse hinzufügen, die alle für die Schnittstelle deklarierten Methode hat, aber nicht selbst als Unterstützung dieser Schnittstelle deklariert. Etwas wie 'TWrap .Create (TStringList.Create)' (Zugegeben, TStringList unterstützt nicht IUnknown, aber Sie bekommen die Idee?) –