Учитывая следующие базовые классы:
public abstract class PurchaseSystemControllerBase<TController, TViewModel> : IInitializable
where TController : PurchaseSystemControllerBase<TController, TViewModel>
where TViewModel : PurchaseSystemViewModelBase<TController, TViewModel> {
protected TViewModel ViewModel { get; private set; }
...
}
public abstract class PurchaseSystemViewModelBase<TController, TViewModel> : ViewModelBase
where TController : PurchaseSystemControllerBase<TController, TViewModel>
where TViewModel : PurchaseSystemViewModelBase<TController, TViewModel> {
protected TController Controller { get; private set; }
...
}
Конкретные реализации заключаются в следующем:
public sealed class PurchaseSystemController : PurchaseSystemControllerBase<PurchaseSystemController, PurchaseSystemViewModel> {
...
}
public sealed class PurchaseSystemViewModel : PurchaseSystemViewModelBase<PurchaseSystemController, PurchaseSystemViewModel> {
...
}
Есть ли способ упростить это, чтобы было возможно следующее:
public sealed class PurchaseSystemController : PurchaseSystemControllerBase<PurchaseSystemViewModel> {
...
}
public sealed class PurchaseSystemViewModel : PurchaseSystemViewModelBase<PurchaseSystemController> {
...
}
Нет, к сожалению, нет - по крайней мере, не то, что я знаю, не теряя при этом никакой безопасности. У меня очень похожая настройка в моем порту протокольных буферов, между типом сообщения и его соответствующим типом строителя.
Если вы с удовольствием объявляете свойства ViewModel
и Controller
только с некоторыми не-генерическими базовыми типами, то это хорошо, но если вам нужно, чтобы эти два точно знали соответствующие типы, у вас остался такой беспорядок.
(Возможно, вам стоит подумать, должны ли ViewModel и Controller знать друг о друге, заметьте).
not that I'm aware of
если Джон Скит не знает об этом, то это подтверждается для нас, ребята :)
Нет, это невозможно, сохраняя при этом полностью сильную типизацию. Вот пример того, как вы можете уменьшить его до более простого набора текста:
public abstract class PurchaseSystemControllerBase : IInitializable {
protected PurchaseSystemViewModelBase ViewModel { get; private set; }
}
public abstract class PurchaseSystemControllerBase<TViewModel>
: PurchaseSystemControllerBase
where TViewModel : PurchaseSystemViewModelBase {
// note: property implementations should prevent this and base.ViewModel
// from getting out of sync
protected new TViewModel ViewModel { get; private set; }
}
public abstract class PurchaseSystemViewModelBase : ViewModelBase {
protected PurchaseSystemControllerBase Controller { get; private set; }
}
public abstract class PurchaseSystemViewModelBase<TController>
: PurchaseSystemViewModelBase
where TController : PurchaseSystemControllerBase {
// note: property implementations should prevent this and base.Controller
// from getting out of sync
protected new TController Controller { get; private set; }
}
public sealed class PurchaseSystemController
: PurchaseSystemControllerBase<PurchaseSystemViewModel> {
}
public sealed class PurchaseSystemViewModel
: PurchaseSystemViewModelBase<PurchaseSystemController> {
}
Этого может быть достаточно, особенно учитывая, что это protected
свойства.