我的域模型具有多个NewsType,它们是NewsItem的子类,如下所示(简化):

public abstract class NewsItem : Entity
{
    public virtual Account Account { get; set; }
    public virtual DateTime DateTime { get; set; }
}


这是NewsItem的几个子类:

public class NewsItemJoiner : NewsItem
{
    public virtual Account AccountJoined { get; set; }
}

public class NewsItemStatus : NewsItem
{
    public virtual string Status { get; set; }
}


在我的MVC应用程序中,我想返回一个Newsitem的集合,其中可能包含NewsItem的许多不同子类。我现在需要做的是遍历每个新闻项,并为该特定类型的NewsItem从相关类中调用Render函数...代码可能会更容易地解释这一点:

public interface IRenderer<T> where T : NewsItem
{
    string Render(T item);
}

public class JoinedRenderer : IRenderer<NewsItemJoiner>
{
    public string Render(NewsItemJoiner item)
    {
        return String.Format("{0} has just joined our music network.", item.AccountJoined.ArtistName);
    }
}

public class StatusUpdateRenderer : IRenderer<NewsItemStatus>
{
    public string Render(NewsItemStatus item)
    {
        return String.Format("<span class='statusupdate'>{0}<span>", item.Status);
    }
}


我需要以某种方式根据NewsItem的类型调用正确的类Render函数。

最佳答案

一种可能:启动时(即在与渲染代码相关的静态构造函数中),遍历程序集中的类并实例化并存储映射到其渲染类型的Dictionary<Type, object>实现实例的IRenderer<T>

(此建议假设渲染器对象是线程安全的,因为您可能最终一次从多个请求线程中调用Render方法。如果它们不是线程安全的,则您需要更改字典<Type, Type>并为每次使用实例化渲染器。)

例如:

public class RenderUtil
{
    static Dictionary<Type, object> s_renderers;

    static RenderUtil()
    {
        s_renderers = new Dictionary<Type, object>();

        foreach (var type in Assembly.GetExecutingAssembly().GetTypes())
        {
            var renderInterface = type.GetInterfaces().FirstOrDefault(
                i => i.IsGenericType &&
                     i.GetGenericTypeDefinition() == typeof(IRenderer<>));

            if (renderInterface != null)
            {
                s_renderers.Add(
                    renderInterface.GetGenericArguments()[0],
                    Activator.CreateInstance(type));
            }
        }
    }

    public static string Render<T>(T item)
    {
        IRenderer<T> renderer = null;
        try
        {
            // no need to synchronize readonly access
            renderer = (IRenderer<T>)s_renderers[item.GetType()];
        }
        catch
        {
            throw new ArgumentException("No renderer for type " + item.GetType().Name);
        }

        return renderer.Render(item);
    }
}


用法:

var newsItem = new NewsItemStatus();

// in your example code, ends up calling StatusUpdateRenderer.Render:
var rendered = RenderUtil.Render(newsItem);


请注意,如果给定类型有多个渲染器,则第一次使用时,RenderUtil类将通过DuplicateKeyException抛出TypeInitializationException

关于c# - C#泛型-根据对象类型查找正确的具体类,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/2274697/

10-11 04:24