9

Ho la seguente dichiarazione di una classe a Delfi XE8:Utilizzando propria classe come vincolo parametro di tipo nella dichiarazione di classe

TestClass = class; 
TestClass = class 
    function test<T: TestClass>(supplier: TFunc<T>): T; // Compiler error 
end; 

che getta il seguente errore del compilatore:

E2086 Type 'TestClass' is not yet completely defined 

Quando aggiungo un'altra classe al mix e usa quella come vincolo invece, funziona bene:

AnotherTestClass = class 
end; 

TestClass = class; 
TestClass = class 
    function test<T: AnotherTestClass>(supplier: TFunc<T>): T; // No Error 
end; 

I susp Il problema è che la dichiarazione del tipo forward non dice ancora abbastanza a Delphi sul tipo TestClass. Questo è forse più evidente in quanto il seguente tentativo di aggirare il problema getta lo stesso errore del compilatore su una linea diversa:

TestClass = class; 
AnotherTestClass = class (TestClass) // Compiler Error 
end; 
TestClass = class 
    function test<T: AnotherTestClass>(supplier: TFunc<T>): T; 
end; 

sto facendo qualcosa di sbagliato e se non, c'è un modo per aggirare questo problema?

+0

Sembra che questo è un bug nel compilatore così ho presentato una [segnalazione di bug qui] (https://quality.embarcadero.com/ sfogliare/RSP-13348). – overactor

+0

Certamente il codice "TestClass = class; AnotherTestClass = class (TestClass) // Errore del compilatore fine;" dovrebbe produrre l'errore mostrato perché Delphi è un compilatore a passaggio singolo. Ma non vedo alcuna ragione per cui la stessa cosa dovrebbe applicarsi al costrutto che stai cercando di creare. Sono disponibili informazioni sufficienti al momento in cui la definizione è valida. – Dsm

+0

@Dsm è d'accordo, ma poiché l'errore del compilatore è lo stesso, ho immaginato che sia un suggerimento a cosa sta andando male. Questo introduce un problema, tuttavia, cosa succede se voglio due classi che usano eachother come un vincolo del parametro di tipo? – overactor

risposta

8

Non stai facendo niente di male. Quello che stai tentando dovrebbe essere possibile, ma il compilatore è, a mio avviso, difettoso. Non esiste un modo praticabile per ovviare a questo senza modificare completamente il design. Un modo per risolvere il problema sarebbe quello di applicare il vincolo in fase di esecuzione. Tuttavia, ciò avrebbe dovuto, ai miei occhi, cambiare completamente il design.

Si noti che in .net ciò che si sta cercando di fare è perfettamente possibile:

class MyClass 
{ 
    private static T test<T>(Func<T> arg) where T : MyClass 
    { 
     return null; 
    } 
} 

La caratteristica generici Delphi è basata su farmaci generici .net e io invece sospetto che il problema si faccia è giù per una svista da parte degli sviluppatori Delphi.

È necessario inviare una segnalazione di bug/richiesta di funzionalità.

Aggiorna 1

LU RD suggerisce una soluzione migliore. Utilizzare un helper di classe:

type 
    TestClass = class 
    end; 

    TestClassHelper = class helper for TestClass 
    function test<T: TestClass>(supplier: TFunc<T>): T; 
    end; 

Ciò consentirà di verificare il vincolo in fase di compilazione. Tuttavia, ti costringe a definire il metodo al di fuori della funzione che è disordinato e ti impedisce di utilizzare un helper di classe per qualsiasi altro scopo. Quindi, dovresti comunque inviare una segnalazione di bug/richiesta di funzionalità nella mia vista.

Update 2

Bug report: RSP-13348

+5

Spostando la funzione in una classe helper compila: 'TestClassHelper = class helper per TestClass test di funzione (fornitore: TFunc ): T; fine; '. –

+3

@LURD Una buona cattura, è in realtà una soluzione valida. Il comportamento e l'API della classe dovrebbero essere identici a quanto previsto, giusto? Tuttavia, è ancora una grande svista nel compilatore, quindi invierò comunque un bug report. – overactor

+2

Si prega di inviare un link al bug report qui. Le persone possono votare per questo se vogliono che le caratteristiche dei generici siano più ortogonali e complete. –