c#如何决定IEnumerable使用哪种实现?

时间:2014-12-14 00:57:06

标签: c# collections ienumerable

我刚开始学习C#,我对以下MSDN代码感到困惑:

IEnumerable<string> strings =
            Enumerable.Repeat("I like programming.", 15);

由于IEnumerable是一个接口而且Enumerable.Repeat&lt;&gt;()返回IEnumerable类型,“字符串”是如何实现的?作为List还是其他容器?

3 个答案:

答案 0 :(得分:0)

在这种情况下没有内部收藏。事实上,有些枚举可能是无限的,所以你不能总是期望内部收集。在这个特定的方法中,有一个保存值的字段和一个计算下一次移动次数的循环。如果它达到指定的计数,则停止迭代。当然,这是使用C#的迭代器功能实现的,这使得实现它变得微不足道。

答案 1 :(得分:0)

这是一个实现细节。 Enumerable<string>.Repeat()的签名承诺结果为IEnumerable<string>,这就是它返回的内容。

此值是以数组形式返回,List还是以任何其他方式生成(后者是这种情况),实现所需的IEnumerable<T>无关紧要。请参阅MSDN上的备注部分,说:

  

此方法通过使用延迟执行来实现。立即返回值是一个对象,它存储执行操作所需的所有信息。在通过直接调用其GetEnumerator方法或在Visual C#中使用foreach或在Visual Basic中使用For Each来枚举对象之前,不会执行此方法表示的查询。

如果您对实际实施感兴趣,请参阅the proposed duplicate

答案 2 :(得分:0)

目前无论如何,返回的类型是:

Enumerable/'<RepeatIterator>d__b5`1'<string>.

您无法将变量定义为tpye,因为它是匿名类型。匿名类型是通过编译具有名称的类型来实现的,该类型虽然有效的.NET是无效的C#,因此您不可能意外地创建具有相同名称的另一种类型。

此特定匿名类型是用于实现yield的排序。同样,当您在C#中编写yield时,这是通过创建实现IEnumerableIEnumerator的.NET类来编译的。

您的代码并不关心任何此类代码,只关心它是否能够实现接口。

为此,请考虑以下方面的有效性:

public IEnumerable<string> SomeStrings()
{
  if(new Random().Next(0, 2) == 0)
    return new HashSet<string>{"a", "b", "c"};
  else
    return new List<string>{"a", "b", "c"};
}

调用代码无法知道它是HashSet<string>还是List<string>而不关心。如果版本2.0实际返回string[]或使用yield,则无关紧。

您可以按照以下方式创建自己的Repeat

public static IEnumerable<T> Repeat<T>(T element, int count)
{
  while(count-- > 0)
    yield return element;
}

我们有一个复杂的问题,因为如果count小于零,我们想抛出一个异常。我们不能只做:

public static IEnumerable<T> Repeat<T>(T element, int count)
{
  if(count < 0)
    throw new ArgumentOutOfRangeException("count");
  while(count-- != 0)
    yield return element;
}

这不起作用,因为抛出不会发生,直到我们实际枚举它(如果我们做的话)为yield - 定义的枚举在第一次枚举之前不运行任何代码。因此我们需要;

public static IEnumerable<T> Repeat<T>(T element, int count)
{
  if(count < 0)
    throw new ArgumentOutOfRangeException("count");
  return RepeatImpl<T>(element, count);
}
private static IEnumerable<T> RepeatImpl<T>(T element, int count)
{
  while(count-- != 0)
    yield return element;
}
相关问题