2013-10-30 7 views
7

Ich bin derzeit mit einem Kompilierfehler fest, niemand in unserer Firma kann helfen und ich finde leider nicht die richtigen Suchmuster für SO oder Google.Delphi - Interface Vererbung mit Generics

Als Code verwende ich 2 Interfaces, geerbt und 2 Klassen, geerbt. Der folgende Code reproduziert den Fehler:

program Project22; 

{$APPTYPE CONSOLE} 
type 
    IStorageObject = interface(IInterface) 
    end; 
    TObjectStorage<T: IStorageObject> = class(TObject) 
    end; 
    IKeyStorageObject<TKey> = interface(IStorageObject) 
    end; 
    TKeyObjectStorage<TKey, T: IKeyStorageObject<TKey>> = class(TObjectStorage<T>) 
    end; 
    TImplementingClass<TKey> = class(TInterfacedObject, IKeyStorageObject<TKey>) 
    end; 
begin 
    TKeyObjectStorage<Integer, TImplementingClass<Integer>>.Create; 
end. 

Der Compiler-Fehler für 'TKeyObjectStorage' ist:

[DCC Error] Project22.dpr(11): E2514 Type parameter 'T' must support interface 'IStorageObject'

Was ich denke, ist, dass der Compiler nicht erkennt, dass Parameter T der Klasse ‚TKeyObjectStorage "richtig. Es sollte korrekt sein, da der gewünschte Typ 'IKeyStorageObject' den übergeordneten Typ IStorageObject hat.

Warum funktioniert das nicht? Was mache ich falsch? Ist das in Delphi nicht möglich?

+0

Haben Sie gerade vollständig die Frage ändern !!? Hast du das Komma einfach durch Semikolon ersetzt? !! Und der Code, den Sie gepostet haben, reicht immer noch nicht aus, um den Fehler anzuzeigen.Bitte tun Sie, was ich vorgeschlagen habe und posten Sie ein ** vollständiges Programm **. Ich habe es dir in meiner Antwort gezeigt. –

+0

Sorry für diesen David, ja ich tat, aber das ',' warf keinen oder diesen Fehler und war nur eine kleine Aufsicht. Sry nochmal. – Hugie

+0

@Hugie, Ändern Sie die Frage nicht, um von ihrem ursprünglichen Problem abzuweichen. Alle Fehler im Original müssen in der Frage bleiben; Erstellen Sie jedoch eine Konsolenanwendung mit dem minimalen Code, um das Problem zu veranschaulichen. und fügen Sie ** diese ** Konsole App in der Frage ein. – Johan

Antwort

9

aktualisiert

Die ursprüngliche Frage hatte ein Problem, das ich (siehe unten) identifiziert. Die Reparatur, die ich dort beschreibe, ist für XE3 und später in Ordnung, aber das folgende Programm kompiliert nicht in XE2. Daraus schließe ich, dass dies ein XE2 Generics Compiler Bug ist.

Wie auch immer, hier ist eine Abhilfe für Delphi XE2:

{$APPTYPE CONSOLE} 
type 
    IStorageObject = interface(IInterface) 
    end; 
    TObjectStorage<T: IStorageObject> = class(TObject) 
    end; 
    IKeyStorageObject<TKey> = interface(IStorageObject) 
    end; 
    TKeyObjectStorage<TKey; T: IKeyStorageObject<TKey>, IStorageObject> = class(TObjectStorage<T>) 
    end; 
    TImplementingClass<TKey> = class(TInterfacedObject, IStorageObject, IKeyStorageObject<TKey>) 
    end; 
begin 
    TKeyObjectStorage<Integer, TImplementingClass<Integer>>.Create; 
end. 

Ursprüngliche Antwort

Es wäre besser gewesen, wenn Sie ein komplettes Programm zur Verfügung gestellt hatten, die den Compiler-Fehler ausgestellt . Sie müssen versuchen, ein Objekt zu instanziieren, um diesen Fehler zu sehen.

Aber ich denke, ich habe Ihr Problem reproduziert. Deshalb glaube ich, dass das Problem, dass dieser Code ist:

TKeyObjectStorage<TKey, T: IKeyStorageObject<TKey>> = ... 

wendet die generische Einschränkung sowohl auf TKey und T. Nun, offenbar nur Sie die Einschränkung auf T anwenden möchten, so müssen Sie schreiben:

TKeyObjectStorage<TKey; T: IKeyStorageObject<TKey>> = ... 

Hier ist ein kurzes Programm, das in Delphi XE3 nach der Änderung erstellt:

{$APPTYPE CONSOLE} 
type 
    IStorageObject = interface(IInterface) 
    end; 
    TObjectStorage<T: IStorageObject> = class(TObject) 
    end; 
    IKeyStorageObject<TKey> = interface(IStorageObject) 
    end; 
    TKeyObjectStorage<TKey; T: IKeyStorageObject<TKey>> = class(TObjectStorage<T>) 
    end; 
    TImplementingClass<TKey> = class(TInterfacedObject, IKeyStorageObject<TKey>) 
    end; 
begin 
    TKeyObjectStorage<Integer, TImplementingClass<Integer>>.Create; 
end. 

Diese ist eine Nuance, das Ändern eines Kommas in ein Semikolon. Die Programmierung durch bedeutungsvolle Interpunktion macht nie viel Spaß. Allerdings ist Ihnen der Unterschied zwischen Kommas und Semikolons in formalen Parameterlisten bekannt, und daher sollte es nicht allzu überraschend sein, die gleiche Unterscheidung zu treffen.

Die documentation macht dieser Geist Sie decken:

Multiple Type Parameters

When you specify constraints, you separate multiple type parameters by semicolons, as you do with a parameter list declaration:

type 
    TFoo<T: ISerializable; V: IComparable> 

Like parameter declarations, multiple type parameters can be grouped together in a comma list to bind to the same constraints:

type 
    TFoo<S, U: ISerializable> ... 

In the example above, S and U are both bound to the ISerializable constraint.

+1

Thx David, ich habe meinen Code zu einer vollständigen Einheit (ohne Instanziierung) bearbeitet und reproduziert den Fehler in einem sauberen Projekt. Und ja, Sie hatten Recht, ich hatte einen kleinen logischen Fehler wegen, ->; aber es war nicht der Fehler, mit dem ich es zu tun habe. Danke für deine Mühe. – Hugie

+0

Ihr Update erzeugt keinen Fehler. Versuch es. Beginnen Sie mit einem neuen Projekt, fügen Sie diese Einheit hinzu und kompilieren Sie sie anschließend. Rate mal was, es kompiliert. Wie ich in meiner Antwort gesagt habe, müssen Sie ein Objekt instanziieren. Ich bin ein bisschen frustriert. Sie müssen lernen, wie Sie einen SSCCE erstellen, damit Sie keine Zeit verschwenden. Ich gehe jetzt zum Mittagessen. Ich hoffe, dass die Frage bis zu meiner Rückkehr geklärt ist. –

+1

Ich habe Ihren Code in XE2 kopiert, es gibt immer noch einen Fehler: '[DCC Fehler] Project22.dpr (11): E2514 Typ Parameter 'T' muss die Schnittstelle 'IStorageObject' in dieser Zeile unterstützen:' TKeyObjectStorage < TKey; T: IKeyStorageObject > = Klasse (TObjectStorage ) ' – Johan