为什么可能将IEnumerable用作方法返回类型或构造函数中

Kon*_*262 1 c# ienumerable interface

我是C#的初学者,而我一直在从事使用IEnumerable的练习。

我想我了解代码,但是我很难理解您为什么会以这种方式使用它

例子1

考虑下面的隔离代码.....

private List<Card> cards;

public Deck (IEnumerable<Card> initialCards)
{
    cards = new List<Card>(initialCards);
}
Run Code Online (Sandbox Code Playgroud)

创建甲板对象并调用此构造函数的代码是...

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);
Run Code Online (Sandbox Code Playgroud)

如果有人首先不介意在下面确认我的理解...

  • 我们创建一个类型为Card的数组,并用Cards填充它
  • 创建Deck对象时,我们将Card []数组传递给Deck构造函数。即使构造函数参数包含IEnumerable类型的参数,由于数组实现IEnumerable也被视为有效。这里有演员表吗?
  • 列表卡通过传递给重载列表构造函数的IEnumerable参数进行初始化。同样,这是强制转换还是某种形式的转换?

使用IEnumerable作为中间类型似乎完全没有意义。该代码仍然可以正常工作,包括foreach循环,如果我将构造函数更改为...,最终将使用该循环。

public Deck (Card [] initialCards)
{
    cards = new List<Card>(initialCards);
}
Run Code Online (Sandbox Code Playgroud)

例子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;
}
Run Code Online (Sandbox Code Playgroud)

这是来自同一类的方法。再次,我不确定为什么当我们仍然可以在字符串数组上执行foreach时为什么将其作为IEnumerable返回。

例子3

public IEnumerable<IWebElement> ElementCollection { get; set; }
Run Code Online (Sandbox Code Playgroud)

这是很笨拙的,但是有人可以向我解释这是什么意思吗?它是IEnumerable类型的公共财产吗?将接口用作属性类型时,它与其他类型有何不同?例如字符串

稍后在代码中将它与LINQ一起使用,这在我的学习中还没有涉及。此示例可能表明,如果我们仅希望迭代某些内容,则可以使用IEnumerable?

非常感谢,

Roy*_* Bg 6

返回接口(在本例中为IEnumerable)或接受它们是面向对象编程中的一种核心方法。这混合了OOP的三个核心原则,尤其是抽象

在长期支持应用程序中,您经常进行更改。在应用程序的开始,您确实需要固定大小的Card集合,因此您确实要使用数组。

private Card[] cards;

public Deck (Card[] initialCards)
{
    cards = initialCards;
}
Run Code Online (Sandbox Code Playgroud)

在某些时候,您需要继续使用固定大小的Card集合。所以你转到List

private List<Card> cards;

public Deck (Card [] initialCards)
{
    cards = new List<Card>(initialCards);
}
Run Code Online (Sandbox Code Playgroud)

在你的应用程序的一部分,你有一个ListCard了。您想将其传递给构造函数。你不能!即使您的内部结构是List,您的构造函数仍在接受数组(Card[])。

您需要从此外部部分将您转换List为数组。为此,您需要遍历所有列表,然后在内存中创建一个新结构-卡阵列。如果您的卡座上有数百万张卡片,可能会很昂贵。

因此,您更改构造函数以接受 List

private List<Card> cards;

public Deck (List<Card> initialCards)
{
    cards = initialCards;
}
Run Code Online (Sandbox Code Playgroud)

在某些时候,您的应用程序会增长。您需要使用独特的纸牌玩游戏。您的应用程序的一部分创建一张HashSet卡片。您不能将其传递给构造函数。该死的构造函数正在接受List。而且,如果将构造函数更改为accepts的构造函数HashSet,则会破坏应用程序传递的另一部分的逻辑List

您希望从应用程序的两个部分传递HashSetList以相同的方式传递信息,而您的平台只是想获取此集合并将其分配给内部结构。

你真正需要的是什么拿的集合Cards,可以是foreach“d后来枚举它的另一个用途。然后你只需告诉应用程序中的其他部分- “伙计们,给我可以列举的对象我真的不在乎,如果它是。SetListArray”。

private IEnumerable<Card> cards;

public Deck (IEnumerable<Card> initialCards)
{
    cards = initialCards;
}
Run Code Online (Sandbox Code Playgroud)

另一方向也是如此。它降低了复杂性。您只是告诉您的消费者,您将给他们一些Card名字来列举。他们需要列出它并查看一些卡名。他们不需要更改名称,添加新卡或其他任何东西。

您不会公开您的实现细节。您只是给您的对象一个机会,以使其对内部结构的了解降至最低。这种隐藏信息的方法可能是封装的一部分。