9

J'ai la déclaration suivante d'une classe dans Delphi XE8:L'utilisation propre classe comme une contrainte de paramètre de type dans la déclaration de classe

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

qui jette l'erreur du compilateur suivant:

E2086 Type 'TestClass' is not yet completely defined 

Quand j'ajoute une autre classe au mélange et utiliser celui-ci comme une contrainte à la place, cela fonctionne bien:

Je susp ect le problème est que la déclaration de type forward ne dit pas assez à Delphi sur le type TestClass pour le moment. Ceci est peut-être plus évident depuis la tentative suivante pour contourner le problème jette la même erreur de compilation sur une autre ligne:

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

que je fais quelque chose de mal et sinon, est-il un moyen de contourner ce problème?

+0

Il semble que ce soit un bogue dans le compilateur donc j'ai soumis un [rapport de bogue ici] (https://quality.embarcadero.com/ browse/RSP-13348). – overactor

+0

Certainement le code "TestClass = class; AnotherTestClass = class (TestClass) // Erreur de compilation end;" devrait produire l'erreur montrée parce que Delphi est un compilateur à passage unique. Mais je ne vois pas pourquoi cela devrait s'appliquer à la construction que vous essayez de créer. Il y a suffisamment d'informations disponibles pour que la définition soit valide. – Dsm

+0

@Dsm est d'accord, mais comme l'erreur du compilateur est la même, j'ai pensé que c'était un indice de ce qui ne va pas. Cela introduit cependant un problème, et si je veux deux classes qui utilisent eachother comme une contrainte de paramètre de type? – overactor

Répondre

8

Vous ne faites rien de mal. Ce que vous essayez devrait être possible, mais le compilateur est, à mon avis, défectueux. Il n'y a pas de moyen viable de contourner cela sans changer complètement le design. Une façon de contourner le problème consiste à appliquer la contrainte lors de l'exécution. Cependant, cela compterait, à mes yeux, comme un changement complet du design.

Notez que dans .net ce que vous essayez de faire est tout à fait possible:

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

La fonction de génériques Delphi a été basée sur les génériques .net et je préfère soupçonner que le problème que vous faites face est en baisse à une surveillance de la part des développeurs Delphi.

Vous devez soumettre un rapport de bogue/demande de fonctionnalité.

Update 1

LU RD propose une meilleure solution. Utilisez un assistant de classe:

type 
    TestClass = class 
    end; 

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

Cela vous permettra d'avoir la contrainte testée au moment de la compilation. Cependant, cela vous oblige à définir la méthode en dehors de la fonction qui n'est pas active, et cela vous empêche d'utiliser une aide de classe à d'autres fins. Donc, vous devriez toujours soumettre un rapport de bogue/demande de fonctionnalité à mon avis.

Mise à jour 2

Rapport de bogue: RSP-13348

+5

Le déplacement de la fonction vers un assistant de classe compile: 'TestClassHelper = assistant de classe pour TestClass test de fonction (fournisseur: TFunc ): T; fin; '. –

+3

@LURD Bonne prise, c'est en fait une solution de contournement viable. Le comportement et l'API de la classe doivent être identiques à ce qui était prévu, n'est-ce pas? C'est toujours un oubli majeur dans le compilateur, donc je vais quand même soumettre un rapport de bogue. – overactor

+2

S'il vous plaît poster un lien vers votre rapport de bogue ici. Les gens peuvent voter pour eux s'ils veulent que les caractéristiques génériques soient plus orthogonales et complètes. –