Как использовать C # Generics для этой реализации, когда Generic Decision основывается на значении DB

2

У нас есть система доставки контента, которая предоставляет множество различных типов контента для устройств. Все содержимое хранится в базе данных с contentID и mediaTypeID.

В этом примере допустим, что MediaType может быть одним из этих 2, но на самом деле их гораздо больше.

Gif
MP3

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

public interface IContentTypeDownloader
{
    MemoryStream GetContentStream();
    Dictionary<string, string> GetHeaderInfo();
}

public class GifDownloader : IContentTypeDownloader
{
    public MemoryStream GetContentStream(int contentID)
    {
        //Retrieve Specific Content gif
    }

    public Dictionary<string, string> GetHeaderInfo()
    {
        //Retrieve Header Info Specific To gifs
    }
}

public class MP3Downloader : IContentTypeDownloader
{
    public MemoryStream GetContentStream(int contentID)
    {
          //Retrieve Specific Content mp3
    }

    public Dictionary<string, string> GetHeaderInfo()
    {
        //Retrieve Header Info Specific To mp3s
    }
}

Что все кажется разумным... Пока я не доберусь до класса менеджера.

public class ContentManager<T> where T : IContentTypeDownloader
{
    public int ContentID { get; set; }

    public MemoryStream GetContent()
    {
        IContentTypeDownloader ictd = default(T);
        return ictd.GetContentStream(this.ContentID);
    }
    ... etc
}

Проблема в том, что мне все равно нужно инициализировать этот тип с помощью определенного IContentTypeDownloader для этого идентификатора MediaTypeID.

И я вернусь к квадрату 1, с ситуацией вроде

if(mediaTypeID == 1)
    ContentManager<GifDownloader> cm = new ContentManager<GifDownloader>();
else if (mediaTypeID == 2)
    ContentManager<MP3Downloader> cm = new ContentManager<MP3Downloader>();

и т.д...

Любая идея о том, как сделать это последнее решение общим на основе значения mediaTyepID, которое выходит из базы данных

  • 0
    У меня была попытка динамически сгенерировать Type t используя Reflection, основываясь на имени MediaType, который вернулся из базы данных. например, "Gif" получит `Type t = Assembly.GetExecutingAssembly (). GetType (mediaTypeName +" Downloader ");", но не радость ...
  • 1
    не стоит упоминать, что он чертовски тесно связан, основываясь на отображении в DB Value => Соглашения об именах имен классов
Показать ещё 3 комментария
Теги:
generics
interface

3 ответа

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

Я duno, если вы можете его создать дальше, чем то, что у вас уже есть.

Возможно, создав класс factory, который просто вернет вам правильный интерфейс, основанный на любом типе носителей, будет более удобным решением.

public static class MediaInterfaceFactory
{
    public static IContentTypeDownloader Create(int mediaId)
    {
       switch (mediaId)
       {
            case 1:
                return new GifDownloader();
            case 2:
                return new Mp3Downloader();

    }
}
  • 0
    Или даже примените подобное решение, но к вашему ContentManager, где фабрика возвращает вам ContentManager на основе mediaId.
  • 0
    Спасибо за предложения, ребята. Перешли с заводским методом. По крайней мере, все в одном месте, если это когда-нибудь станет более динамичным, я посмотрю на его рефакторинг в БД с активатором для генерации класса Types.
1

Я думаю, что вполне приемлемо иметь простой шаблон дизайна Factory. Конечно, вы можете сходить с ума и иметь словарь Enum, представляющий ваш тип контента как ключ и фактический тип как значение. И затем в вашем классе Factory возьмите Enum и используйте Activator.CreateInstance, чтобы вернуть правильный тип.

public enum MediaTypes
        {
            GIF,
            MPEG
        }


Dictionary<Enum, Type> dictionary = new Dictionary<Enum, Type>() { { MediaTypes.GIF, typeof(GifDownloader) } };

public static IContentTypeDownloader Create(MediaTypes mediaType)
    {
      Type type= dictionary[mediaType];
      IContentTypeDownloader contentObject = Activator.CreateInstance(type);

    }

вы можете использовать это с mediaId, конечно же, в словаре.

1

Думаю, я могу так поступить:

  • Определите атрибут, который вы размещаете на своих конкретных загрузчиках типов контента:

    [MediaType (ID = 1)]

  • При запуске сканируйте свою сборку и настройте словарь типа contentID → экземпляр загрузчика типа контента, связанного с идентификатором (вы выяснили, что это с атрибутом)

  • У вашего типа контент-загрузчиков есть такой метод, как IContentTypeDownloader Clone();

Затем ваш код должен быть уменьшен до

downloader = dictionary[mediaType].Clone();

С помощью контейнера DI по вашему выбору вы можете заменить словарь и сканировать, например. Конфигурация, основанная на соглашениях.

Ещё вопросы

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