Упростить круговые общие ограничения в C #?

1

Учитывая следующие базовые классы:

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> {
    ...
}
  • 0
    FWIW, вы должны стараться избегать такого рода самоссылающихся обобщений, когда это возможно (хотя у него есть свои применения). Ссылка: blogs.msdn.com/b/ericlippert/archive/2011/02/03/…
Теги:
generics

2 ответа

3
Лучший ответ

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

Если вы с удовольствием объявляете свойства ViewModel и Controller только с некоторыми не-генерическими базовыми типами, то это хорошо, но если вам нужно, чтобы эти два точно знали соответствующие типы, у вас остался такой беспорядок.

(Возможно, вам стоит подумать, должны ли ViewModel и Controller знать друг о друге, заметьте).

  • 9
    not that I'm aware of если Джон Скит не знает об этом, то это подтверждается для нас, ребята :)
1

Нет, это невозможно, сохраняя при этом полностью сильную типизацию. Вот пример того, как вы можете уменьшить его до более простого набора текста:

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 свойства.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню