2016-04-30 18 views
1

我是C#的初學者程序員,我剛剛開始使用IEnumerable的練習。爲什麼你可以使用IEnumerable作爲方法的返回類型或者在構造函數中

我想我明白的代碼,但我掙扎理解爲什麼你會不會使用這種方式

例1

考慮以下隔離代碼.....

private List<Card> cards; 

public Deck (IEnumerable<Card> initialCards) 
{ 
    cards = new List<Card>(initialCards); 
} 

創建甲板對象並調用這個構造函數的代碼是...

Card[] cardArray = new Card[numberOfCards]; 
for (int i = 0; i < numberOfCards; i++) 
{ 
    cardArray[i] = new Card((Suits)random.Next(0, 4), (Values)random.Next(0, 12)); 
} 
deck1 = new Deck(cardArray); 

如果有人先不介意確認低於我的理解......

  • 我們創造型卡的數組,並用卡
  • 我們通過卡[]數組中的甲板構造填充當創建一個Deck對象時。即使構造函數參數包含一個IEnumerable類型的參數,但它被認爲是有效的,因爲數組實現了IEnumerable。 這裏發生了演員嗎?
  • 列表卡片被傳遞給重載列表構造函數的IEnumerable參數初始化。 再一次,這是一個演員或某種轉換?

使用IEnumerable作爲中間類型似乎完全沒有意義。該代碼仍然有效相同,包括foreach循環如果我改變構造到最終使用...

public Deck (Card [] initialCards) 
{ 
    cards = new List<Card>(initialCards); 
} 

例2

public IEnumerable<string> GetCardNames() 
{ 
    string[] stringArray = new string[cards.Count]; 
    for (int i = 0; i < stringArray.Length; i++) 
    { 
     stringArray[i] = cards[i].ToString(); 
    } 
    return stringArray; 
} 

這是來自同一個類中的方法。再次,我不確定爲什麼這是作爲一個IEnumerable返回,當我們仍然可以做一個字符串數組的foreach。

例3

public IEnumerable<IWebElement> ElementCollection { get; set; } 

這是非常noobish,但有人可以給我解釋一下這是什麼意思嗎?它是IEnumerable類型的公共屬性嗎?當你使用一個接口作爲屬性類型時,它與其他類型有何不同?例如字符串

這與LINQ稍後在代碼中一起使用,這在我的學習中還沒有得到。可能這個例子表明,如果我們只想遍歷某些東西,IEnumerable可以被使用嗎?

非常感謝,

+0

可枚舉是某些序列操作的泛化 - 這些操作包括由數組提供的子集。所有數組(或列表)*實現* IEnumerable。 – user2864740

回答

4

返回接口(在這種情況下IEnumerable)或接受它們是面向對象編程中的一個核心方法。這混合了面向對象的三個核心原則,特別是抽象

在長期支持應用程序中,您經常進行更改。在你的應用程序開始時,你需要固定大小的Card集合,所以你確實使用了一個數組。

private Card[] cards; 

public Deck (Card[] initialCards) 
{ 
    cards = initialCards; 
} 

在某些時候,你需要在Card收集的非固定尺寸移動。所以,你移動到List

private List<Card> cards; 

public Deck (Card [] initialCards) 
{ 
    cards = new List<Card>(initialCards); 
} 

在你的應用程序的一部分,你有一個CardList。你想把它傳遞給你的構造函數。你不能!即使你的內部結構是List,你的構造函數仍然接受一個數組(Card[])。

您需要從此外部零件將您的List轉換爲數組。爲此,您需要遍歷所有列表,並在內存中創建一個新結構 - 一組卡片。如果你的套牌擁有數百萬張牌,這可能會很昂貴。

所以你改變你的構造函數接受List

private List<Card> cards; 

public Deck (List<Card> initialCards) 
{ 
    cards = initialCards; 
} 

在某些時候,你的應用程序的增長。你需要玩獨一無二的牌。你的應用程序的一部分創建了一張HashSet卡片。你不能將它傳遞給構造函數。該死的構造函數正在接受List's。如果您將構造函數更改爲接受HashSet's,則會破壞來自應用程序的另一部分的邏輯,該部分通過List

您希望從應用程序的兩個部分以相同的方式通過HashSetList,並且您的套牌只是爲了獲取該集合並將其分配給內部結構。

你真正需要的是採取Cards的集合,可以是foreach'd並在稍後枚舉它以用於另一種用法。然後你只要告訴你的應用程序的其他部分 - 「夥計們,給我一個可以枚舉的對象,我真的不在乎它是否是SetListArray」。

private IEnumerable<Card> cards; 

public Deck (IEnumerable<Card> initialCards) 
{ 
    cards = initialCards; 
} 

另一種方式也是如此。它降低了複雜性。你只要告訴你的消費者,你會給他們一個Card名字的集合來枚舉。他們需要列出並看到一些名片。他們不需要更改名稱,添加新卡或其他任何東西。

你不公開你的實現細節。你只要給自己的對象機會,儘量不要理解其內部結構。這種隱藏信息的方式可以作爲封裝的一部分。

1

例1

我們創造型卡的數組,並用卡

填充

不是一個問題,但正確的。

創建 卡座對象時,我們將卡片[]數組傳遞給卡座構造函數。即使構造函數參數包含IEnumerable類型的參數 ,但它被認爲是有效的,因爲數組實現了 IEnumerable。在這裏發生了演員?

這是一種隱式類型轉換。當類型實現接口時,不需要向下轉換,因爲類型是「該類型的」。例如,你不會要求每個談論水果獼猴桃的人在他們的意思是「獼猴桃」和「水果」之間有所不同,因爲獼猴桃具有水果的所有特性。

列表卡片使用在 中傳遞的IEnumerable參數初始化爲重載列表構造函數。再次,這是一個演員或一個 轉換某種?

如果您檢查,List包含一個IEnumerable構造函數。由於您的構造函數是通過IEnumerable傳遞的,因此不需要將IEnumerable轉換爲另一個IEnumerable。

使用IEnumerable作爲中間類型似乎完全沒有意義。該代碼仍然有效相同,包括foreach循環如果我改變構造到最終使用...

public Deck (Card [] initialCards) 
{ 
    cards = new List<Card>(initialCards); 
} 

這不是毫無意義的,不斷變化的構造函數,這將打破試圖發送任何代碼而是向構造函數列表。

實施例2

public IEnumerable<string> GetCardNames() 
{ 
    string[] stringArray = new string[cards.Count]; 
    for (int i = 0; i < stringArray.Length; i++) 
    { 
     stringArray[i] = cards[i].ToString(); 
    } 
    return stringArray; 
} 

這是從相同類的方法。再次,我不知道爲什麼這是 作爲一個IEnumerable返回時,當我們仍然可以做一個字符串 數組的foreach。

通常你會在接口中放入類似這樣的方法,並保證每個實現都可以返回IEnumerable。通常在使用IEnumerables時,可以使用yield和巧妙的邏輯推遲計算,同時調用GetCardNames(),因爲Array將直接強制執行計算。使用IEnumerable的原因有很多,但通常它們指向某種「保證」,無法保證Arrays符合要求。

例3

public IEnumerable<IWebElement> ElementCollection { get; set; } 

這是非常noobish,但有人可以給我解釋一下,這是 說什麼?它是IEnumerable類型的公共屬性嗎?當你使用一個 接口作爲屬性類型時,它與其他類型有什麼不同? 例如字符串

這是用於LINQ後面的代碼,我還沒有在我的 學習。可能這個例子表明,如果我們只希望 迭代某些東西,可以使用IEnumerable?

這是一個公開的IEnumerable屬性,你有一個默認的支持者說,等了IEnumerable保證它可以遍歷,這是一個相當有力的保障,因爲它允許搜索和更多的東西。只是因爲你可以迭代它並不意味着項目是連續的或其他任何東西,因此實現可能會有所不同。這是接口的優勢之一。

代碼中的不同位置也可以爲IEnumerable屬性分配不同的類型。有些可能會發送它的列表,其他人可能會發送它的數組也可以將計算推遲到需要發生的時間。

1

其他答案是非常徹底的。這是一個稍微短一點:

數組,列表和其他集合類型全部實現IEnumerable。將方法參數聲明爲IEnumerable表示該方法不會「關心」實際類型,只要它實現IEnumerable即可。

如果您的方法是通過集合去for...each,那麼爲什麼指定它需要是一個數組或列表?當你不那麼具體時,沒有必要更具體。

這也是一種告訴方法期望對傳遞給它的參數做些什麼的方法。如果一個方法採用IEnumerable<T>的參數,它實際上是說:「我只是想拿你的收藏並枚舉它,我不會添加或刪除項目。」

如果參數是List<T>IList<T>那麼接收它的方法可能會添加或刪除項目。

不太常見,爲了說明起見 - 如果將數組傳遞給方法,該方法可能會改變數組的排序順序。 (說實話,這不是我通常關心的可能性。)

當然,指定這些類型不能絕對強制這些行爲,但它是一種方法來傳達其行爲的方式。你添加到列表中。您列舉IEnumerable

相關問題