2013-10-30 17 views
7

Attualmente sono bloccato con un errore di compilazione, nessuno nella nostra azienda può aiutare e purtroppo non trovo i modelli di ricerca corretti per SO o google.Delphi - ereditarietà dell'interfaccia con i generici

Come codice sto usando 2 interfacce, ereditate e 2 classi, ereditate. Il seguente codice riproduce l'errore:

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. 

L'errore del compilatore per 'TKeyObjectStorage' è:

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

Quello che penso è che il compilatore non riconosce tale parametro T del TKeyObjectStorage della classe' 'correttamente. Dovrebbe essere corretto, poiché il tipo desiderato "IKeyStorageObject" ha il tipo principale IStorageObject.

Perché non funziona? Che cosa sto facendo di sbagliato? Non è possibile a Delphi?

+0

Hai appena cambiare completamente la questione !!? Hai appena sostituito quella virgola con il punto e virgola? !! E il codice che hai postato non è ancora abbastanza per mostrare l'errore.Per favore, fai ciò che ho suggerito e pubblica un ** programma completo **. Ti ho mostrato come nella mia risposta. –

+0

Ci scusiamo per questo David, Sì, ma il ',' non ha generato un errore o questo errore ed è stato solo un leggero svista. Sry di nuovo. – Hugie

+0

@Hugie, non cambiare la domanda per deviare dal suo problema originale. Eventuali errori presenti nell'originale devono rimanere nella domanda; tuttavia creare un'app console con il codice minimo per dimostrare il problema. e incolla ** quell'app console nella domanda. – Johan

risposta

9

Aggiornamento

La domanda originale aveva un problema che ho individuato (vedi sotto). Tuttavia, la correzione che descrivo è valida per XE3 e versioni successive, ma il programma riportato di seguito non viene compilato in XE2. Quindi concludo che questo è un bug del compilatore generico XE2.

In ogni caso, ecco una soluzione per 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. 

risposta originale

Sarebbe stato meglio se si fosse previsto un programma completo che espone l'errore del compilatore . È necessario tentare di creare un'istanza di un oggetto per vedere quell'errore.

Ma, penso di aver riprodotto il tuo problema. Quindi credo che il problema è che questo codice:

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

vale il vincolo generico sia TKey e T. Ora, chiaramente desideri solo il vincolo da applicare al T quindi è necessario scrivere:

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

Ecco un breve programma che compila in seguito alla modifica Delphi XE3:

{$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. 

Questo è piuttosto una sfumatura, il cambio di una virgola in un punto e virgola. Programmare con una punteggiatura significativa non è mai molto divertente. Detto questo, hai familiarità con la differenza tra virgole e punti e virgola in liste parametriche formali e quindi non dovrebbe essere troppo sorprendente vedere la stessa distinzione tracciata qui.

Il documentation fa coprire questo si badi bene:

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, ho modificato il mio codice su un'unità completa (senza istanziazione) e riproduce l'errore in un progetto pulito. E sì, avevi ragione, ho avuto un errore logico minore dovuto a, ->; ma non era l'errore con cui ho a che fare. Grazie per il tuo impegno. – Hugie

+0

L'aggiornamento non ha prodotto alcun errore. Provalo. Inizia con un nuovo progetto, aggiungi quell'unità e poi compila. Indovina, compila. Come ho detto nella mia risposta, è necessario creare un'istanza di un oggetto. Sono un po 'frustrato da questo. Devi imparare come creare un SSCCE in modo da non perdere tempo. Adesso vado a pranzo. Spero che la domanda sia risolta al momento del mio ritorno. –

+1

Ho copiato il codice in XE2, restituisce ancora un errore: '[Errore DCC] Project22.dpr (11): E2514 Il parametro di tipo 'T' deve supportare l'interfaccia 'IStorageObject'' su questa riga:' TKeyObjectStorage < TKey; T: IKeyStorageObject > = class (TObjectStorage ) ' – Johan