C# - 将List <baseclass>“强制转换”为List <derivedclass>的简单方法?</derivedclass> </baseclass>

时间:2010-12-12 01:21:51

标签: c# asp.net linq abstraction base-class

我建立的网站有三种主要类型的&#34;在线新闻刊物&#34;:ArticleBlogPostColumnPost。在整个网站上,我有各种控件输出这些列表,混合在一起并且不混合。因此,在许多控件上我有一个文章列表,而在其他控件上我可以有一个博客帖子和列帖子的列表。在一些地方,我甚至有一个文章列表,博客文章和专栏文章。所以我创建了一个围绕所有三个名为Publication的包装类。我以前的类继承了这样的:

BasePage : System.Web.UI.Page

Article : BasePage

BlogPost : BasePage

ColumnPost : BasePage

many other pages types : BasePage

使用我的新Publication包装器,它们看起来像:

BasePage : System.Web.UI.Page

Publication : BasePage

Article : Publication

BlogPost : Publication

ColumnPost : Publication

现在我可以这样做:

var dataSource = new List<Publication>();

articlesForThisControl().ForEach(a => dataSource.Add(a));
blogPostsForThisControl().ForEach(bp => dataSource.Add(bp));
columnPostsForThisControl().ForEach(cp => dataSource.Add(cp));

... dataSource.SortByDate() ...

现在最重要的是,我在C#中使用中介模式来调解许多可能需要重叠数据的竞争控件。我曾经有一个ArticleMediator,但现在我已将其更改为PublicationMediator

我的问题:

从基类列表中检索派生类列表的最佳/最简单方法是什么?所以我的调解员基本上接受List<Publication>并返回List<Publication>。如果我知道列表中的所有内容都是Article,那么将其恢复为List<Article>的简单方法是什么?现在我正在做以下似乎是很多代码,但如果我应该这样做,那我就没事了。我只是想知道是否有更简单的方法:

List<Article> articles = new List<Article>();

PublicationMediator.CalculateResults();
PublicationMediator.GetResults(this.UniqueID).PublicationList.Where(p => p is Article).ToList().ForEach(p => articles.Add((Article)p));

PublicationList属性是调解器已决定允许当前控件使用的返回List<Publication>。我知道虽然我只想要List<Article>所以我必须浏览列表中的每个Publication,并确保它是Article然后我必须将其添加到实际List<Article>。有更简单的方法吗?

我不想更改调解员以返回List<Article>的原因是因为在某些地方我需要BlogPostColumnPost所以我实际上需要绑定我的转发到List<Publication>并在ItemDataBound内我可以看到当前项目是BlogPost还是ColumnPost

更新

我接受了接受的答案并将其扩展为:

public static List<T> GetSublist<T>(this List<Publication> publications) where T : Publication {
  return publications.OfType<T>().ToList<T>();
}

3 个答案:

答案 0 :(得分:4)

既然你说如果我知道列表中的所有内容都是文章我建议使用Enumerable.Cast

PublicationList.Cast<Article>().ToList();

如果您的假设是假的,这将抛出异常,这可能是一件好事,因为这可能表明您的程序中存在错误。

答案 1 :(得分:3)

您可以使用Enumerable.OfType扩展名方法:

PublicationMediator.CalculateResults();

List<Article> articles = PublicationMediator.GetResults(this.UniqueID)
                                            .PublicationList
                                            .OfType<Article>()
                                            .ToList();

答案 2 :(得分:0)

简单的答案是,没有直接的方法可以做到这一点,至少不像你在你的例子中给出的那样。 您正在寻找的是与框架调用协方差和逆变的两个特征有关。如您所见,这些特征存在于许多其他语言中:LINK

但是在C#中,接口和委托级别只有协方差。以下是有助于您理解这些概念的文章的链接:

Article that explains the concepts of covariance and contravariance.

Definition of covariance in multiple programming languages.

Another excellent article of covariance and contravariance.

The problems that some fear with covariance.

有了这个,你仍然有以下选择:

  1. 手工改造是最明显的。
  2. 转换您的逻辑以使用协方差与接口的功能。
  3. 最后,使用类似于名为Automapper的知名库,这样可以简化您的转换。
  4. 我知道这些解决方案都不是很自然,但是在微软在以下版本的C#中引入列表中的协方差之前,这是唯一的事情。