目前无论如何,返回的类型是:
Enumerable/'<RepeatIterator>d__b5`1'<string>.
您不能将变量定义为 tpye,因为它是匿名类型。匿名类型是通过编译一个名称来实现的,虽然有效的 .NET 不是有效的 C#,但您不可能意外地创建另一个具有相同名称的类型。
这种特殊的匿名类型是用于实现yield 的类型。同样,当您在 C# 中编写 yield 代码时,这是通过创建实现 IEnumerable 和 IEnumerator 的 .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;
}