Когда Name
возвращает ссылку, она возвращает this
- поэтому, когда экземпляр на самом деле экземпляр CorporationBuilder
, эта ссылка возвращается как обычно. То, что метод объявлен как возвращающий OrganizationBuilder
, не означает, что только возвращает ссылку OrganizationBuilder
. Он возвращает ссылку на экземпляр OrganizationBuilder
instance или производный класс (или, конечно, null
).
Когда затем вызывается метод Write
, это виртуальный метод, поэтому проверяется тип времени выполнения объекта, чтобы найти используемую реализацию. Тип времени выполнения по-прежнему CorporationBuilder
, поэтому используется переопределение, указанное в этом типе.
Что касается того, как заставить Name()
возвращать соответствующий тип - для этого, в основном, потребуется больше обобщений. Это может быть сделано, но это боль - я сделал нечто подобное в Protocol Buffers, но это не приятно. Вы также сделаете OrganizationBuilder
родовым в TContact
и TBuilder
, а также Name
вернете TBuilder
с помощью приведения от this
до TBuilder
. Тогда CorporationBuilder
будет либо общим, либо просто наследоваться от OrganizationBuilder<Corporation, CorporationBuilder>
.
РЕДАКТИРОВАТЬ: Да, я вижу проблему (о которой я забыл раньше). Вы также можете захотеть иметь конкретный неуниверсальный класс с именем CorporationBuilder
, чтобы избежать рекурсивных обобщений:
public class OrganizationBuilder :
OrganizationBuilder<Organization, OrganizationBuilder>
Вы также можете переименовать OrganizationBuilder
в OrganizationBuilderBase
, чтобы избежать путаницы:)
(Вам не нужно, чтобы CorporationBuilder
был сам по себе универсальным, если он находится в нижней части иерархии.)
Однако, это становится чрезвычайно сложным. Возможно, вы захотите хотя бы рассмотреть избегая наследования здесь. Удалите дженерики и заставьте OrganizationBuilder
иметь a CorporationBuilder
вместо того, чтобы извлекать из него.
По сути, этот шаблон всегда усложняется через некоторое время - вам нужно, чтобы каждый уровень был универсальным, за исключением конечных узлов, которые всегда должны быть неуниверсальными, чтобы избежать проблемы рекурсии, которую вы уже видели. Это боль.