简体   繁体   English

当泛型决策基于数据库值时,如何使用C#泛型进行此实现

[英]How do I use C# Generics for this implementation when the Generic Decision is based on a DB Value

We have a content delivery system that delivers many different content types to devices. 我们有一个内容交付系统,可以将许多不同的内容类型交付给设备。 All the content is stored in a database with a contentID & mediaTypeID . 所有内容都使用contentIDmediaTypeID存储在数据库中。

For this example lets assume the MediaType can be one of these 2 but in reality theres many more of them. 对于此示例,假设MediaType可以是这2种之一,但实际上有更多种。

Gif
MP3

Because the content is stored in different places based on mediatype and requires different headers to be sent, theres a big nasty piece of legacy code that essentially switches on each mediatype and sets the correct parameters. 由于内容根据媒体类型存储在不同的位置,并且需要发送不同的标头,因此存在大量的讨厌代码,这些代码实际上在每种媒体类型上切换并设置正确的参数。 *I'd like to change this into a more generic implementation. *我想将其更改为更通用的实现。 So heres what I've got so far in my wireframe 所以这是到目前为止我在线框中所拥有的

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
    }
}

Which all seems sensible... Until I get to the Manager Class. 这一切似乎都是明智的。。。直到我进入经理班。

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
}

The problem is, I still need to initialise this type with the specific IContentTypeDownloader for that mediaTypeID. 问题是,我仍然需要使用针对该mediaTypeID的特定IContentTypeDownloader初始化此类型。

And I'm back to square 1, with a situation like 我回到第一个方框,情况像

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

etc... 等等...

Anyone any idea on how to make this last decision generic based on the value of the mediaTyepID that comes out of the Database 任何人都可以根据数据库中出现的mediaTyepID的值来决定如何使最后一个决定通用

I duno if you can generify it any further than what you have already. 我不知道您是否可以将其扩大化。

Perhaps creating a factory class which just returns you the correct Interface based on whatever media type would be a neater solution ie 也许创建一个工厂类,该类将根据任何更整洁的解决方案(即哪种媒体类型)返回正确的接口,即

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

    }
}

I think I may go about this like that: 我想我可能会这样:

  • Define an attribute you place on your specific content type downloaders: 定义一个放置在特定内容类型下载器上的属性:

    [MediaType(ID = 1)] [MediaType(ID = 1)]

  • Upon startup scan your assembly and set up a dictionary of style contentID -> instance of the content type downloader associated with the id (you figured that out with the attribute) 启动时,扫描您的程序集并设置一个字典contentID->与id关联的内容类型下载器实例的字典(您已通过属性确定了这一点)

  • Have your content type downloaders some method like IContentTypeDownloader Clone(); 让您的内容类型下载器具有某些方法,例如IContentTypeDownloader Clone();。

Then your code should be reduced to 然后,您的代码应简化为

downloader = dictionary[mediaType].Clone();

With a DI Container of your choice you may be able to replace the dictionary and scanning with eg a convention-based configuration. 使用您选择的DI容器,您可以替换字典并使用基于约定的配置进行扫描。

I think it is totally acceptable to have a simple Factory Design Pattern. 我认为拥有简单的工厂设计模式是完全可以接受的。 Of course you can go really crazy and have a Dictionary of Enum representing you content type as key and the actual Type as value. 当然,您可能会发疯,并拥有一个Enum字典,将您的内容类型表示为键,而将实际类型表示为值。 And then in your factory class take in the Enum and use Activator.CreateInstance to return the right type. 然后在您的工厂类中,使用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);

    }

you can use this with mediaId's of course as well in the dictionary.. 您当然也可以在字典中将它与mediaId一起使用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM