2010-12-12 29 views
1

我正在建立一個網站,它有三種主要類型的「在線新聞出版物」:Article,BlogPostColumnPost。整個網站我有各種控制輸出這些列表,混合在一起,不混合。所以在很多控件上,我有一個文章列表,而在其他控件上,我可以列出博客文章和專欄文章。在一些地方,我甚至有一篇文章,博客文章和專欄文章。所以我創建了一個名爲Publication的包裝類。我以前的類繼承,像這樣:C# - 簡單的方法來「投」列表<BaseClass>列表<DerivedClass>?

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內我可以,如果看到當前項目是BlogPostColumnPost

UPDATE

我把接受的答案,並把它做成一個擴展:

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

回答

3

可以使用Enumerable.OfType擴展方法:

PublicationMediator.CalculateResults(); 

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

謝謝! 'OfType()'似乎做了我已經做的相同的過濾器,但是爲了我的擴展。這正是我需要的。 – 2010-12-13 15:42:30

4

既然你說如果我知道列表中的所有內容都是文章我建議我們荷蘭國際集團Enumerable.Cast:如果你的假設是錯誤的,這可能是一件好事,因爲這可能是一個跡象表明有在你的程序中的錯誤

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

這會拋出異常。

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的知名庫,它將簡化您的轉換。

我知道這些解決方案都不是非常自然的,但它是微軟在C#的以下版本中引入列表中的協變之前唯一剩下的東西。