我建立的网站有三种主要类型的"在线新闻刊物":Article
,BlogPost
和ColumnPost
。在整个网站上,我有各种控件输出这些列表,混合在一起并且不混合。因此,在许多控件上我有一个文章列表,而在其他控件上我可以有一个博客帖子和列帖子的列表。在一些地方,我甚至有一个文章列表,博客文章和专栏文章。所以我创建了一个围绕所有三个名为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>
的原因是因为在某些地方我需要BlogPost
和ColumnPost
所以我实际上需要绑定我的转发到List<Publication>
并在ItemDataBound
内我可以看到当前项目是BlogPost
还是ColumnPost
。
更新
我接受了接受的答案并将其扩展为:
public static List<T> GetSublist<T>(this List<Publication> publications) where T : Publication {
return publications.OfType<T>().ToList<T>();
}
答案 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.
有了这个,你仍然有以下选择:
我知道这些解决方案都不是很自然,但是在微软在以下版本的C#中引入列表中的协方差之前,这是唯一的事情。