C# 在方法调用时或枚举响应时是否枚举IEnumerable

C# 在方法调用时或枚举响应时是否枚举IEnumerable,c#,ienumerable,C#,Ienumerable,我想知道在调用方法或枚举方法的返回时,是否枚举了方法的IEnumerable参数,假设我们有以下代码: IEnumerable进程列表(IEnumerable列表) { foreach(列表中的var元素) { 收益返回流程要素(要素); } } 我最好奇的是如何编写类似Linq的扩展。只有在枚举了ProcessList(enumerable)的结果时才会枚举list(enum2): static void Main(string[] args) { var enumerable =

我想知道在调用方法或枚举方法的返回时,是否枚举了方法的IEnumerable参数,假设我们有以下代码:

IEnumerable进程列表(IEnumerable列表)
{
foreach(列表中的var元素)
{
收益返回流程要素(要素);
}
}
我最好奇的是如何编写类似Linq的扩展。

只有在枚举了
ProcessList
enumerable
)的结果时才会枚举
list
enum2
):

static void Main(string[] args)
{
    var enumerable = Enum1();
    Console.WriteLine("Enum1 retrieved");
    var enum2 = Enum2(enumerable);
    Console.WriteLine("Enum2 called");
    foreach (var e in enum2)
    {
        Console.WriteLine(e);
    }
}

private static IEnumerable<string> Enum1()
{
    Console.WriteLine("Enum1");
    yield return "foo";
}

private static IEnumerable<string> Enum2(IEnumerable<string> enumerable)
{
    Console.WriteLine("Enum2");
    foreach (var s in enumerable)
    {
        yield return s;
    }
}
最后三行仅在进入
foreach
循环时打印。

仅在枚举
ProcessList
enum2
)的结果时才枚举
列表(
enumable
):

static void Main(string[] args)
{
    var enumerable = Enum1();
    Console.WriteLine("Enum1 retrieved");
    var enum2 = Enum2(enumerable);
    Console.WriteLine("Enum2 called");
    foreach (var e in enum2)
    {
        Console.WriteLine(e);
    }
}

private static IEnumerable<string> Enum1()
{
    Console.WriteLine("Enum1");
    yield return "foo";
}

private static IEnumerable<string> Enum2(IEnumerable<string> enumerable)
{
    Console.WriteLine("Enum2");
    foreach (var s in enumerable)
    {
        yield return s;
    }
}

最后三行仅在进入
foreach
循环时打印。

使用
yield
关键字意味着此代码片段将仅在需要时进行计算,以提供您使用的结果。换句话说,这不会导致评估:

var processed = ProcessList(unprocessed);
结果列表的内容无关紧要,因此不会对其进行评估。但是,如果您这样做:

var processed = ProcessList(unprocessed).ToList();
var processed = ProcessList(unprocessed);
foreach (var x in processed)
{
    DoSomething(x);
}
var processed = ProcessList(unprocessed);
foreach (var x in processed.Take(10))
{
    DoSomething(x);
}
这将要求它计算
IEnumerable
,这将导致它运行您的代码。同样,如果您这样做:

var processed = ProcessList(unprocessed).ToList();
var processed = ProcessList(unprocessed);
foreach (var x in processed)
{
    DoSomething(x);
}
var processed = ProcessList(unprocessed);
foreach (var x in processed.Take(10))
{
    DoSomething(x);
}
它将依次为每个元素运行
ProcessElement()
方法。若要进一步了解这一点,请执行以下操作:

var processed = ProcessList(unprocessed).ToList();
var processed = ProcessList(unprocessed);
foreach (var x in processed)
{
    DoSomething(x);
}
var processed = ProcessList(unprocessed);
foreach (var x in processed.Take(10))
{
    DoSomething(x);
}

因为您只使用结果列表的前10项,所以它将只对这10项运行
ProcessElement()
方法。其余的代码只会在您使用它们时进行评估。

使用
yield
关键字意味着这段代码只会在需要时进行评估,以提供您使用的结果。换句话说,这不会导致评估:

var processed = ProcessList(unprocessed);
结果列表的内容无关紧要,因此不会对其进行评估。但是,如果您这样做:

var processed = ProcessList(unprocessed).ToList();
var processed = ProcessList(unprocessed);
foreach (var x in processed)
{
    DoSomething(x);
}
var processed = ProcessList(unprocessed);
foreach (var x in processed.Take(10))
{
    DoSomething(x);
}
这将要求它计算
IEnumerable
,这将导致它运行您的代码。同样,如果您这样做:

var processed = ProcessList(unprocessed).ToList();
var processed = ProcessList(unprocessed);
foreach (var x in processed)
{
    DoSomething(x);
}
var processed = ProcessList(unprocessed);
foreach (var x in processed.Take(10))
{
    DoSomething(x);
}
它将依次为每个元素运行
ProcessElement()
方法。若要进一步了解这一点,请执行以下操作:

var processed = ProcessList(unprocessed).ToList();
var processed = ProcessList(unprocessed);
foreach (var x in processed)
{
    DoSomething(x);
}
var processed = ProcessList(unprocessed);
foreach (var x in processed.Take(10))
{
    DoSomething(x);
}

因为您只使用结果列表的前10项,所以它将只对这10项运行
ProcessElement()
方法。其余部分只有在您开始使用时才会进行评估。

您可以通过在回路中放置制动点来了解自己。但我的最佳猜测是,它是在枚举结果时枚举的。如果您想创建类似Linq的扩展方法,应该由Jon Skeet检查。您可以编写返回无限长序列的枚举(例如,
,而(true)返回1;
)您将能够调用返回枚举的方法,而不会花费无限长的时间。只有“枚举枚举器”将开始遍历循环。谢谢!虽然我可以自己测试一下,但我认为这些答案对其他人来说是一个很好的参考。你可以通过在你的循环中放置一个制动点来发现你自己。但我的最佳猜测是,它是在枚举结果时枚举的。如果您想创建类似Linq的扩展方法,应该由Jon Skeet检查。您可以编写返回无限长序列的枚举(例如,
,而(true)返回1;
)您将能够调用返回枚举的方法,而不会花费无限长的时间。只有“枚举枚举器”将开始遍历循环。谢谢!虽然我可以自己测试一下,但我认为这些答案对其他人来说是一个很好的参考。