1

我正在建立一个网站,其中包含三种主要类型的“在线新闻出版物”: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

我的问题:

从基类列表中检索派生类列表的最佳/最简单方法是什么?所以我的中介基本上接受 aList<Publication>并返回 a List<Publication>。如果我知道列表中的所有内容都是 a Article,那么有什么简单的方法可以将其取回并将其转换为 a 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>中介已决定允许使用当前控件的返回值。我知道虽然我只想要 aList<Article>所以我必须遍历Publication列表中的每一个并确保它是 anArticle然后我必须将它添加到实际的List<Article>. 有没有更简单的方法来做到这一点?

我不想更改调解器以返回 aList<Article>的原因是因为在某些地方我需要两者BlogPostColumnPost所以我实际上需要将我的转发器绑定到 aList<Publication>并且在ItemDataBound我可以看到当前项目是否为BlogPostor ColumnPost

更新

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

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

3 回答 3

4

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

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

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

于 2010-12-12T01:51:46.553 回答
3

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

PublicationMediator.CalculateResults();

List<Article> articles = PublicationMediator.GetResults(this.UniqueID)
                                            .PublicationList
                                            .OfType<Article>()
                                            .ToList();
于 2010-12-12T01:25:24.227 回答
0

简单的答案是,没有直接的方法可以做到这一点,至少不像您在示例中给出的那样。您正在寻找的内容与框架的两个特性有关,即协变和逆变。这些特征在许多其他语言中都有,您可以在此处看到:LINK

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

解释协变和逆变概念的文章。

多种编程语言中协方差的定义。

另一篇关于协变和逆变的优秀文章。

有些人担心协方差的问题。

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

  1. 手工改造,是最明显的。
  2. 转换您的逻辑以使用接口的协方差特性。
  3. 最后,使用一个名为 Automapper 的知名库之类的东西,这将使您的转换变得简单。

我知道这些解决方案都不是很自然,但这是唯一剩下的事情,直到微软在以下 C# 版本中引入列表中的协方差。

于 2010-12-12T02:04:52.357 回答