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

У нас есть система доставки контента, которая доставляет много разных типов контента на устройства. Весь контент хранится в базе данных с 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, которое выходит из базы данных

Ответы [ 3 ]

2 голосов
/ 10 июля 2009

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

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

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

    }
}
1 голос
/ 10 июля 2009

Я думаю, что вполне приемлемо иметь простой шаблон проектирования фабрики. Конечно, вы можете сойти с ума и иметь словарь Enum, представляющий тип контента в качестве ключа и фактический тип в качестве значения. А затем в вашем фабричном классе возьмите 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 голос
/ 10 июля 2009

Я думаю, что могу пойти так:

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

    [MediaType (ID = 1)]

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

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

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

downloader = dictionary[mediaType].Clone();

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

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