9

У меня есть следующее объявление класса в Delphi X Е8:Использование собственного класса в качестве параметра типа ограничения в объявлении класса

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

Который проливает следующее сообщение об ошибке компилятора:

E2086 Type 'TestClass' is not yet completely defined 

Когда я добавляю другой класс в смеси и использовать его в качестве ограничения вместо этого, он отлично работает:

AnotherTestClass = class 
end; 

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

I susp Проблема заключается в том, что объявление прямого типа еще не сообщает Delphi о типе TestClass. Это, пожалуй, более очевидна, так как следующая попытка обойти проблему бросает ту же самую ошибку компилятора на другой линии:

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

Я делаю что-то неправильно, и если нет, то есть ли способ обойти эту проблему?

+0

кажется, что это ошибка в компиляторе, так что я представил [сообщение об ошибке здесь] (https://quality.embarcadero.com/ просмотреть/RSP-13348). – overactor

+0

Конечно, код «TestClass = class; AnotherTestClass = class (TestClass) // Ошибка компилятора end;" должен показать ошибку, потому что Delphi является компилятором с одним проходом. Но я не вижу причин, по которым то же самое следует применять к конструкции, которую вы пытаетесь создать. В то время достаточно информации, чтобы определение было действительным. – Dsm

+0

@ Dsm согласился, но поскольку ошибка компилятора такая же, я понял, что это намек на то, что происходит не так. Однако это создает проблему, но если я хочу, чтобы два класса использовали eachother как ограничение параметра типа? – overactor

ответ

8

Вы не делаете ничего плохого. То, что вы пытаетесь, должно быть возможно, но компилятор, на мой взгляд, неисправен. Нет никакого жизнеспособного способа обойти это без полного изменения дизайна. Один из способов обойти эту проблему - обеспечить принуждение к ограничению во время выполнения. Однако это, на мой взгляд, могло бы полностью изменить дизайн.

Обратите внимание, что в .net, что вы пытаетесь сделать, это вполне возможно:

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

Функция дженерики Delphi была основана на .net дженериков, и я подозреваю, что проблема вы сталкиваетесь вниз по недосмотру со стороны разработчиков Delphi.

Вы должны отправить сообщение об ошибке/запрос функции.

Update 1

LU RD предлагает лучшее решение. Использовать классный помощник:

type 
    TestClass = class 
    end; 

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

Это позволит вам испытывать ограничения во время компиляции. Тем не менее, это заставляет вас определять метод вне функции, которая является неопрятной, и она останавливает вас с помощью помощника класса для любых других целей. Таким образом, вы должны представить отчет об ошибке/запрос функции на мой взгляд.

Update 2

Отчет об ошибке: RSP-13348

+5

Перемещение функции компилятору класса: 'TestClassHelper = помощник класса для TestClass Функциональный тест (поставщик: TFunc ): T; конец; '. –

+3

@ LURD Хорошая добыча, это действительно жизнеспособное решение. Поведение и API класса должны быть идентичны тому, что было предназначено, не так ли? Тем не менее, это большой надзор в компиляторе, поэтому я все равно отправлю отчет об ошибке. – overactor

+2

Пожалуйста, разместите ссылку на свой отчет об ошибке здесь. Люди могут голосовать за него, если они хотят, чтобы характеристики дженериков были более ортогональными и полными. –