Тесная связь с родственными классами? - PullRequest
5 голосов
/ 12 декабря 2010

У меня есть специальная система мастера, которая до сих пор была вполне подходящей. Для большинства мастеров страницы могут быть сконструированы довольно общим образом, поэтому только один класс реализует эти типы страниц. Однако некоторые из них должны быть разработаны по индивидуальному заказу, поэтому для таких типов страниц существует абстрактный базовый класс. Из-за некоторых недостатков в конструкторе VS страница сама по себе не может быть элементом управления UI, а также может быть абстрактным классом с общими параметрами (которые существуют для свободного программирования). Итак, я выбрал один вариант - реализовать страницу для двух классов: один для пользовательского интерфейса (который наследуется от UserControl и может быть спроектирован), а другой - для страницы. Страница содержит экземпляр элемента управления пользовательского интерфейса и встраивает его в себя для отображения. Не оптимально, но работает.

Теперь из-за этой установки возникает проблема: существует тесная связь между классом управления пользовательским интерфейсом и классом страницы. Обычно это не такая уж большая проблема, за исключением того, что страницы могут быть получены для создания специализированных версий страниц. Таким образом, производные элементы управления и страницы также тесно связаны с собой . Поэтому, когда у меня есть переменные-члены, свойства и методы в классе элемента управления и страницы, которые печатаются соответственно для элемента управления или класса страницы (т. Е. Класс элемента управления будет иметь свойство Page, которое указывает на страницу, в которую встроен элемент управления ), мы сталкиваемся с большой проблемой с производными классами. Каждый производный класс должен каким-то образом изменять тип этих членов. Я думал о том, чтобы включить параметр общего типа, который позволял бы типизировать эти элементы:

public class BaseControl<TControl, TPage>
    where TPage : BasePage<TPage, TControl>
    where TControl : BaseControl<TControl, TPage> {
    public TPage Page { get { ... } set { ... } }
    ...
}

public class BasePage<TPage, TControl>
    where TPage : BasePage<TPage, TControl>
    where TControl : BaseControl<TControl, TPage> {
    public TControl Control { get { ... } set { ... }
    ...
}

public class DerivedControl<TControl, TPage> : BaseControl<TControl, TPage>
    where TControl : DerivedControl<TControl, TPage>
    where TPage : DerivedPage<TPage, TControl> { }

public class DerivedPage<TPage, TControl> : BasePage<TPage, TControl>
    where TControl : DerivedControl<TControl, TPage>
    where TPage : DerivedPage<TPage, TControl> { }

Очевидно, что это тот тип мусора в стиле C ++, которого я бы хотел избежать. Помимо уродства, это создает реальную проблему, в которой нужно создавать запечатанные «листовые» классы, чтобы обойти проблему бесконечной рекурсии, которую приносит нам CRTP.

И все же альтернативы также не привлекательны. Я мог бы сделать так, чтобы у этих членов был фиксированный тип базового типа, и я мог бы проводить кастинг везде. Это не обеспечивает безопасность типов и требует бессмысленных приведений (я уже знаю, что тип будет таким-то, но компилятор этого не делает). Я мог бы смириться с этим и объединить страницу и класс управления в одну, без abstract или общих параметров типа. Это разрушает беглую систему программирования или делает ее намного сложнее в реализации, с большим повторением (я объясню, если необходимо, но давайте просто предположим, что эта часть моего проекта является законной).

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

1 Ответ

3 голосов
/ 12 декабря 2010

У меня очень аналогичный код в моем порту буферов протокола , где тип сообщения и компоновщик для этого типа сообщения связаны.

По сути, вы пытаетесь выразить отношения, которые дженерики C # делают неловкими.

В моем случае большая часть этого скрыта в сгенерированном коде, поэтому разработчику не нужно делать очень много ... но все равно это уродливо. Я искал альтернативы, но не нашел. Я думаю, что то, что у вас есть, может быть настолько хорошим, насколько вы можете получить, боюсь ... если предположить, что вы написали об ограничениях VS и других ваших требованиях, это правильно. Если вы обнаружите, что можете работать в совершенно ином дизайне, это замечательно, но если вам нужны два связанных типа, я думаю, что весь этот «мусор» необходим: (

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...