Одно из распространенных применений этого связано с концепцией самотипов: параметр типа, который разрешает текущий тип. Допустим, вы хотите определить интерфейс с clone()
методом. clone()
Метод всегда должен возвращать экземпляр класса , на котором он был вызван. Как вы объявляете этот метод? В системе дженериков, которая имеет свои типы, это легко. Вы просто говорите, что это возвращается self
. Так что, если у меня есть класс Foo
, метод clone должен быть объявлен для возврата Foo
. В Java и (из простого поиска) C # это не вариант. Вместо этого вы видите объявления, подобные тому, что вы видите в этом классе. Важно понимать, что это не то же самое, что и тип личности, и ограничения, которые он предоставляет, более слабые. Если у вас есть Foo
и Bar
класс, который оба являются производными отBasePage
, вы можете (если я не ошибаюсь) определить Foo для параметризации Bar
. Это может быть полезно, но я думаю, что, как правило, в большинстве случаев это будет использоваться как самопечатание, и просто понятно, что даже если вы можете обмануть и заменить другими типами, это не то, что вы должны делать. Я давно обдумал эту идею, но пришел к выводу, что это не стоит затраченных усилий из-за ограничений дженериков Java. Обобщения C #, конечно, более полнофункциональны, но, похоже, имеют то же ограничение.
В другой раз этот подход используется, когда вы создаете графоподобные типы, такие как деревья или другие рекурсивные структуры. Объявление позволяет типам соответствовать требованиям Page, но дополнительно уточняет тип. Вы можете увидеть это в древовидной структуре. Например Node
, параметр может быть параметризован с помощью, Node
чтобы реализации могли определить, что это не просто деревья, содержащие какой-либо тип узла, а определенный подтип узла (обычно их собственный тип). Я думаю, что это больше того, что здесь происходит.