9

Ich habe die folgende Deklaration einer Klasse in Delphi XE8:Mit eigenen Klasse als Typ-Parameter Einschränkung in Klassendeklaration

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

, das die folgenden Compiler-Fehler führt:

E2086 Type 'TestClass' is not yet completely defined 

Als ich hinzufügen eine andere Klasse für den Mix und verwenden Sie diese als Einschränkung stattdessen, es funktioniert gut:

AnotherTestClass = class 
end; 

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

Ich susp Das Problem ist, dass die Forward-Typ-Deklaration Delphi noch nicht genug über den Typ TestClass informiert. Dies ist vielleicht noch deutlicher, da der folgende Versuch, um das Problem auf einer anderen Linie, die die gleichen Compiler-Fehler führt zu arbeiten:

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

Mache ich etwas falsch, und wenn nicht, gibt es eine Möglichkeit, um dieses Problem?

+0

Es scheint, dass dies einen Fehler in dem Compiler ist, damit ich einen [Bug-Report hier] eingereicht haben (https://quality.embarcadero.com/ Durchsuchen/RSP-13348). – overactor

+0

Natürlich der Code "TestClass = Klasse; AnotherTestClass = Klasse (TestClass) // Compiler Fehler Ende;" sollte den gezeigten Fehler erzeugen, da Delphi ein Single-Pass-Compiler ist. Aber ich sehe keinen Grund, warum das gleiche für das Konstrukt gilt, das Sie erstellen möchten. Zu diesem Zeitpunkt sind genügend Informationen verfügbar, damit die Definition gültig ist. – Dsm

+0

@Dsm stimmte zu, aber da der Compiler-Fehler der gleiche ist, dachte ich, es ist ein Hinweis darauf, was falsch läuft. Dies führt jedoch zu einem Problem, was ist, wenn ich zwei Klassen möchte, die sich gegenseitig als Typparameter-Einschränkung verwenden? – overactor

Antwort

8

Sie machen nichts falsch. Was Sie versuchen, sollte möglich sein, aber der Compiler ist meiner Meinung nach defekt. Es gibt keine praktikable Möglichkeit, dies zu umgehen, ohne das Design komplett zu verändern. Eine Möglichkeit zur Umgehung des Problems besteht darin, die Einschränkung zur Laufzeit zu erzwingen. Das würde in meinen Augen jedoch das Design komplett verändern.

Beachten Sie, dass in .net, was Sie durchaus möglich, versuchen zu tun ist:

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

Die Delphi-Generika-Funktion auf .net Generika basierte und ich eher vermuten, dass das Problem, das Sie Gesicht ist bis auf ein Versehen seitens der Delphi-Entwickler.

Sie sollten einen Fehlerbericht/eine Funktionsanfrage senden.

aktualisieren 1

LU RD schlägt eine bessere Abhilfe. Verwenden Sie eine Klasse Helfer:

type 
    TestClass = class 
    end; 

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

Dies ermöglicht Ihnen, die Einschränkung bei der Kompilierung getestet haben. Es zwingt Sie jedoch, die Methode außerhalb der Funktion zu definieren, die unordentlich ist, und es stoppt Sie, einen Klassenhelfer für jeden anderen Zweck zu verwenden. Daher sollten Sie eine Fehlerbericht/Feature-Anfrage aus meiner Sicht senden.

Update 2

Bugreport: RSP-13348

+5

Das Verschieben der Funktion in einen Klassenhelfer kompiliert: 'TestClassHelper = Klassenhelfer für TestClass Funktionstest (Lieferant: TFunc ): T; Ende; '. –

+3

@LURD Guter Haken, das ist eigentlich eine praktikable Lösung. Das Verhalten und API der Klasse sollte identisch sein mit dem, was beabsichtigt war, oder? Es ist immer noch ein großes Versehen im Compiler, also werde ich immer noch einen Fehlerbericht einreichen. – overactor

+2

Bitte poste hier einen Link zu deinem Fehlerbericht. Menschen können dafür stimmen, wenn sie möchten, dass die generischen Merkmale orthogonaler und vollständiger sind. –