Создание универсального c сервисного интерфейса, который использует универсальные c параметры - PullRequest
2 голосов
/ 20 апреля 2020

Я пытаюсь использовать универсальные c# для создания универсального c интерфейса, который служит основой для построения всех моих служб листинга. Однако у меня есть проблема с определением.

Базовые классы

abstract class ListingParams { }

abstract class ListingDTO<T> where T : ListingItemDTO
{
    public List<T> Items{ get; set; }
}

abstract class ListingItemDTO { }

Конкретный пример

class HListingParams : ListingParams { }
class HListing : ListingDTO<HItem> { }
class HItem : ListingItemDTO { }

Интерфейс

interface IListingToolsService<in TFilter, out U, V>
    where TFilter : ListingParams
    where U : ListingDTO<V> where V : ListingItemDTO
{
    int Count(TFilter parameters);

    U Get(TFilter parameters);
}

Здесь начинается проблема, поскольку метод Get возвращает тип generi c, я должен добавить третий параметр c generi к интерфейсу.

Если я хочу создать конкретная реализация этого интерфейса, я должен создать что-то вроде этого:

class HListingToolsService : IListingToolsService<ListingParams, HListing, HItem>
{
    public int Count(ListingParams parameters) => throw new NotImplementedException();
    public HListing Get(ListingParams parameters) => throw new NotImplementedException();
}

Однако по определению HListing не является обобщенным c, потому что он был определен с использованием HItem.

Есть ли способ создать этот интерфейс только с двумя параметрами, чтобы не повторять уже определенный тип?

Ответы [ 2 ]

1 голос
/ 20 апреля 2020

Вы можете немного изменить свой код, преобразовать ListingDTO<T> в интерфейс и сделать универсальный c параметр типа T ковариантным. В этом случае вам также следует изменить тип Items на IEnumerable<T>, поскольку List<T> является инвариантом.

interface IListingDTO<out T> where T : ListingItemDTO
{
    public IEnumerable<T> Items { get; }
}

Затем внедрите его в HListing class

class HListing : IListingDTO<HItem>
{
    public IEnumerable<HItem> Items { get; }
}

После что вы можете обновить интерфейс IListingToolsService и избавиться от параметра типа V generi c и его ограничения

interface IListingToolsService<in TFilter, out U>
    where TFilter : ListingParams
    where U : IListingDTO<ListingItemDTO>
{
    int Count(TFilter parameters);

    U Get(TFilter parameters);
}

Наконец, реализовать HListingToolsService class

class HListingToolsService : IListingToolsService<ListingParams, HListing>
{
    public int Count(ListingParams parameters) => throw new NotImplementedException();
    public HListing Get(ListingParams parameters) => throw new NotImplementedException();
}

Объявление коварианта IListingDTO<out T> позволяет использовать HListing (который реализует этот интерфейс) в реализации сервиса

1 голос
/ 20 апреля 2020

Это может немного изменить ваш дизайн, но я бы попробовал заменить следующий код чем-то, что не принимает параметр типа. Таким образом, мы можем инкапсулировать ListingDTO в класс, который напрямую не принимает параметр типа.

abstract class ListingItemBase : ListingItemDTO { }

abstract class ListingDTOBase : ListingDTO<ListingItemBase>
{
    public List<ListingItemBase> Items { get; set; }
}

И заставить HListing наследовать ListingDTOBase:

class HListing : ListingDTOBase { }

После этого вы сможете определить интерфейс без использования параметра типа V:

interface IListingToolsService<in TFilter, out U>
                            where TFilter : ListingParams
                            where U : ListingDTOBase
{
    int Count(TFilter parameters);

    U Get(TFilter parameters);
}

и службы:

class HListingToolsService : IListingToolsService<ListingParams, HListing>
{
    public int Count(ListingParams parameters) => throw new NotImplementedException();
    public HListing Get(ListingParams parameters) => throw new NotImplementedException();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...