?现在我正在执行以下操作,这似乎是很多代码,但如果这是我应该做的,那么我就很好。我只是想知道是否有更简单的方法:C# - “投射”的简单方法列表<基类>列出? 基类>
我正在构建一个包含三种主要类型的“在线新闻出版物”的网站: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
并返回一个 List
。如果我知道列表中的所有内容都是Article
,那么有什么简单的方法可以将其返回并将其转换为List
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
,中介器已决定允许使用当前控件。我知道我只想要一个 List
所以我必须浏览列表中的每个 Publication
并确保它是一个 Article
然后我必须将其添加到实际的 List
中。有没有更简单的方法来做到这一点?我不想更改中介器以返回 List
的原因是因为在某些地方我需要 BlogPost
和 ColumnPost
所以我实际上需要将我的转发器绑定到 List
并在 ItemDataBound
中我可以查看当前项目是 BlogPost
还是 <代码>ColumnPost。更新
我接受了答案并将其变成扩展:
public static List<T> GetSublist<T>(this List<Publication> publications) where T : Publication {
return publications.OfType<T>().ToList<T>();
}
I'm building a site that has three main types of "online news publications": Article
, BlogPost
, and ColumnPost
. Across the site I have various controls that output lists of these, mixed together and unmixed. So on many controls I have a list of articles while on other controls I can have a list of blog posts and column posts. In a few places I even have a list of articles, blog posts, and column posts. So I created a wrapper class around all three called Publication
. My previous classes inherited like so:
BasePage : System.Web.UI.Page
Article : BasePage
BlogPost : BasePage
ColumnPost : BasePage
many other pages types : BasePage
With my new Publication
wrapper, they look like:
BasePage : System.Web.UI.Page
Publication : BasePage
Article : Publication
BlogPost : Publication
ColumnPost : Publication
Now I can do something like this:
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() ...
Now to top it off, I'm using the mediator pattern in C# to mediate among many competing controls that might want overlapping data. I used to have an ArticleMediator
but now I've changed it to be a PublicationMediator
instead.
My question:
What is the best/easiest way to retrieve a list of a derived class from a list of the base class? So my mediator essentially takes in a List<Publication>
and returns a List<Publication>
. If I know everything in the list is an Article
, what's an easy way to get it back and cast it as a List<Article>
? Right now I'm doing the following which seems to be a lot of code but if this is how I should do it, then I'm fine. I'm just wondering if there's an easier way:
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));
The PublicationList
property is the returned List<Publication>
that the mediator has decided the current control is allowed to use. I know though that I only want a List<Article>
so I have to go through each Publication
in the list and make sure it's an Article
then I have to add that to an actual List<Article>
. Is there an easier way to do this?
The reason I don't want to change the mediator to return a List<Article>
is because in some places I need both BlogPost
and ColumnPost
so I actually need to bind my repeaters to a List<Publication>
and within the ItemDataBound
I can see if the current item is BlogPost
or ColumnPost
.
UPDATE
I took the accepted answer and made it into an extension:
public static List<T> GetSublist<T>(this List<Publication> publications) where T : Publication {
return publications.OfType<T>().ToList<T>();
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
既然您说如果我知道列表中的所有内容都是文章,我建议使用
Enumerable.Cast
:如果您的假设为假,这将引发异常,这可能是一件好事,因为这可能表明存在错误你的程序。
Since you said If I know everything in the list is an Article I'd recommend using
Enumerable.Cast
:This will throw an exception if your hypothesis is false, which is probably a good thing as that is possibly an indication that there is a bug in your program.
您可以使用 Enumerable.OfType 扩展方法:
You can use the Enumerable.OfType extension method:
简单的答案是,没有直接的方法可以做到这一点,至少不像您在示例中给出的那样。
您正在寻找的内容与框架的两个功能(称为协变和逆变)相关。这些特征也存在于许多其他语言中,您可以在此处看到:LINK。
然而,在 C# 中,仅在接口和委托级别存在协变。以下是可帮助您理解这些概念的文章链接:
解释协变和逆变概念的文章。
多种编程语言中协方差的定义。
另一篇关于协变和逆变的优秀文章。
一些人担心协方差的问题。
有了这个,您仍然有以下选择:
我知道这些解决方案都不是很自然,但这是唯一剩下的事情,直到 Microsoft 在以下版本的 C# 中引入列表中的协方差。
The simple answer is, there is no a direct way to do it, at least not as you give in your example.
What you're looking for is related to two features of the framework calls covariance and contravariance. These characteristics are present in many other languages as you can see here: LINK.
However in C# there is only covariance at interfaces and delegates level. Here are links to articles that will help you to understand these concepts:
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.
With this you still have the following choices:
I know none of these solutions are very natural, but it's the only thing left until Microsoft introduces the covariance in Lists in the following versions of C#.