IEnumerable 方法管道

发布于 2025-01-14 10:56:34 字数 3287 浏览 3 评论 0 原文

代码来自 https://ayende.com/blog/3082/管道和过滤器的可枚举方法

问题 已注册 3 个操作。 首先获取系统中的所有进程。 第二个过滤过程。 第三个写入进程名称。

但使用的是yield和GetEnumerator。

current = operation.Execute(current); 行被执行三次,第一个操作的输出列表是第二个操作的输入。而且它只是一个列表(操作)。 我不明白 private readonly List> 中存储的方式和内容操作 = new List>(); ???因为 foreach 有 3 个执行。执行 enumerator.MoveNext() 时执行的某种委托?好的,但是我们有 Foreach,它是执行的吗?在使用 GetEnumerator 之前三次。 所以列出“操作”应该是 ovverriden ...? :) 我想了解一种机制。在使用 enumerator.MoveNext() 执行之前如何存储此“委托”。以及它的用途是什么?

class Program
    {
        static void Main(string[] args)
        {
            var trivialProcess = new Pipeline<Process>();

            trivialProcess.Register(new GetAllProcesses());
            trivialProcess.Register(new LimitByWorkingSetSize());
            trivialProcess.Register(new PrintProcessName());

            trivialProcess.Execute();
        }
    }


    interface IOperation<T>
    {
        IEnumerable<T> Execute(IEnumerable<T> input);

    }

    class GetAllProcesses : IOperation<Process>
    {
        public IEnumerable<Process> Execute(IEnumerable<Process> input)
        {
            Debug.WriteLine("GetAllProcesses Execute");
            return Process.GetProcesses();
        }
    }

    class LimitByWorkingSetSize : IOperation<Process>
    {
        public IEnumerable<Process> Execute(IEnumerable<Process> input)
        {
            int maxSizeBytes = 50 * 1024 * 1024;
            Debug.WriteLine("LimitByWorkingSetSize Enter");
            foreach (Process process in input)
            {
                Debug.WriteLine("LimitByWorkingSetSize foreach");
                if (process.WorkingSet64 > maxSizeBytes)
                {
                    Debug.WriteLine("LimitByWorkingSetSize yield");
                    yield return process;
                }
            }

        }
    }

    class PrintProcessName : IOperation<Process>
    {
        public IEnumerable<Process> Execute(IEnumerable<Process> input)
        {
            Debug.WriteLine("PrintProcessName Enter");
            foreach (Process process in input)
            {
                Debug.WriteLine("PrintProcessName  print");
                Console.WriteLine(process.ProcessName);
            }
            Debug.WriteLine("PrintProcessName break");
            yield break;
        }
    }

    class Pipeline<T>
    {
        private readonly List<IOperation<T>> operations = new List<IOperation<T>>();

        public Pipeline<T> Register(IOperation<T> operation)
        {
            operations.Add(operation);
            return this;
        }

        public void Execute()
        {
            IEnumerable<T> current = new List<T>();

            foreach (IOperation<T> operation in operations)
            {
                current = operation.Execute(current);
            }
            IEnumerator<T> enumerator = current.GetEnumerator();
            while (enumerator.MoveNext()) ;
        }
    }

code from https://ayende.com/blog/3082/pipes-and-filters-the-ienumerable-appraoch

Question
There is registered 3 operations.
First gets all Processes in system.
Second filters processes.
Third writes processes names.

But yield is used and GetEnumerator.

Line current = operation.Execute(current); is executed three times and output list from first operation is input of second opetation. And it is only one list (operations ).
I dont understand How and what is stored in private readonly List<IOperation<T>> operations = new List<IOperation<T>>(); ??? as foreach has three execution. Some kind of delegate which is executed when enumerator.MoveNext() is executed? OK, but we have Foreach, which is executed? three times before GetEnumerator is used.
So list "operations " should be ovverriden ... ? :)
I would like to understand a mechanism. How this "delegates" is stored before execution enumerator.MoveNext() is used. and at what it is used?

class Program
    {
        static void Main(string[] args)
        {
            var trivialProcess = new Pipeline<Process>();

            trivialProcess.Register(new GetAllProcesses());
            trivialProcess.Register(new LimitByWorkingSetSize());
            trivialProcess.Register(new PrintProcessName());

            trivialProcess.Execute();
        }
    }


    interface IOperation<T>
    {
        IEnumerable<T> Execute(IEnumerable<T> input);

    }

    class GetAllProcesses : IOperation<Process>
    {
        public IEnumerable<Process> Execute(IEnumerable<Process> input)
        {
            Debug.WriteLine("GetAllProcesses Execute");
            return Process.GetProcesses();
        }
    }

    class LimitByWorkingSetSize : IOperation<Process>
    {
        public IEnumerable<Process> Execute(IEnumerable<Process> input)
        {
            int maxSizeBytes = 50 * 1024 * 1024;
            Debug.WriteLine("LimitByWorkingSetSize Enter");
            foreach (Process process in input)
            {
                Debug.WriteLine("LimitByWorkingSetSize foreach");
                if (process.WorkingSet64 > maxSizeBytes)
                {
                    Debug.WriteLine("LimitByWorkingSetSize yield");
                    yield return process;
                }
            }

        }
    }

    class PrintProcessName : IOperation<Process>
    {
        public IEnumerable<Process> Execute(IEnumerable<Process> input)
        {
            Debug.WriteLine("PrintProcessName Enter");
            foreach (Process process in input)
            {
                Debug.WriteLine("PrintProcessName  print");
                Console.WriteLine(process.ProcessName);
            }
            Debug.WriteLine("PrintProcessName break");
            yield break;
        }
    }

    class Pipeline<T>
    {
        private readonly List<IOperation<T>> operations = new List<IOperation<T>>();

        public Pipeline<T> Register(IOperation<T> operation)
        {
            operations.Add(operation);
            return this;
        }

        public void Execute()
        {
            IEnumerable<T> current = new List<T>();

            foreach (IOperation<T> operation in operations)
            {
                current = operation.Execute(current);
            }
            IEnumerator<T> enumerator = current.GetEnumerator();
            while (enumerator.MoveNext()) ;
        }
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

把回忆走一遍 2025-01-21 10:56:35

我不明白私有只读列表中存储的方式和内容操作 = new List(); ???

它是一个 IOperation 列表,在本例中是 GetAllProcessesLimitByWorkingSetSizePrintProcessName 类的实例。所有这些类都实现 IOperation 接口,因此能够被视为 IOperation,并且允许存储在列表中。

因为foreach有3次执行

是的,但这只是设置了 LimitByPrintProcesses 类的调用链,因为它们的 Execute 是生成器(功能yield) - 它们只有在被枚举时才会被执行。 current = operation.Execute(current); 将立即执行 GetAllExecute,因为这不会 yield< /code> 任何内容(但可以对其进行修改),但在 PrintProcess 中运行代码(依赖于 LimitBy),仅当 MoveNext() 发生时才会发生。 PrintProcess 捕获控制流,并且在枚举时不会产生任何内容。

执行 enumerator.MoveNext() 时执行的委托?

我怀疑这是在深入研究这种情况下的收益机制(但你在下面再次询问它,所以..)

好的,但是我们有 Foreach,它会被执行吗?

给出的代码示例中有很多foreach。执行 PrintProcess 的 Execute 会运行一个 foreach,它枚举链中下一个方法(LimitByExecute)的输出 - 它本身也包含一个 foreach。如果您在调试器中单步执行,并在每个 foreach 下的 { 上设置断点,您将看到它在 PrintProcess限制LimitBy 正在生成 PrintProcess 正在枚举的某些循环传递的数据。 PrintProcesses 不会为进一步的操作产生任何东西,因此控制在这两个操作之间来回传递,直到 LimitBy 没有任何东西可以提供,此时,PrintProcess 将不再枚举任何内容

所以列表“操作”应该是 ovverriden ...?

我怀疑这是一个重写错误。代码中没有任何内容会覆盖 operations 列表;它是被覆盖的当前。它只是作为记住上次输出是什么的一种方式,因此它可以在每次循环时成为输入。严格来说,一开始就没有必要将其初始化为新的 List,因为该链中的第一个 Execute 不会对其输入执行任何操作。代码>

在使用 enumerator.MoveNext() 执行之前如何存储“委托”。它的用途是什么?

我认为你本质上是在问yield是如何工作的;简而言之,编译器会为您编写一些类,这些类实现了一个枚举器,该枚举器根据您使用的围绕 yield 关键字的逻辑生成值。长答案是相当可怕的,而不是你想自己写的东西,这就是为什么我们通常非常乐意让编译器生成它而不是在引擎盖下查看:

#define DEBUG
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
namespace ConsoleApp7net5
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            Pipeline<Process> pipeline = new Pipeline<Process>();
            pipeline.Register(new GetAllProcesses());
            pipeline.Register(new LimitByWorkingSetSize());
            pipeline.Register(new PrintProcessName());
            pipeline.Execute();
        }
    }
    internal interface IOperation<T>
    {
        IEnumerable<T> Execute(IEnumerable<T> input);
    }
    internal class GetAllProcesses : IOperation<Process>
    {
        public IEnumerable<Process> Execute(IEnumerable<Process> input)
        {
            Debug.WriteLine("GetAllProcesses Execute");
            return Process.GetProcesses();
        }
    }
    internal class LimitByWorkingSetSize : IOperation<Process>
    {
        [CompilerGenerated]
        private sealed class <Execute>d__0 : IEnumerable<Process>, IEnumerable, IEnumerator<Process>, IDisposable, IEnumerator
        {
            private int <>1__state;

            private Process <>2__current;

            private int <>l__initialThreadId;

            private IEnumerable<Process> input;

            public IEnumerable<Process> <>3__input;

            public LimitByWorkingSetSize <>4__this;

            private int <maxSizeBytes>5__1;

            private IEnumerator<Process> <>s__2;

            private Process <process>5__3;

            Process IEnumerator<Process>.Current
            {
                [DebuggerHidden]
                get
                {
                    return <>2__current;
                }
            }

            object IEnumerator.Current
            {
                [DebuggerHidden]
                get
                {
                    return <>2__current;
                }
            }

            [DebuggerHidden]
            public <Execute>d__0(int <>1__state)
            {
                this.<>1__state = <>1__state;
                <>l__initialThreadId = Environment.CurrentManagedThreadId;
            }

            [DebuggerHidden]
            void IDisposable.Dispose()
            {
                int num = <>1__state;
                if (num == -3 || num == 1)
                {
                    try
                    {
                    }
                    finally
                    {
                        <>m__Finally1();
                    }
                }
            }

            private bool MoveNext()
            {
                try
                {
                    int num = <>1__state;
                    if (num != 0)
                    {
                        if (num != 1)
                        {
                            return false;
                        }
                        <>1__state = -3;
                        goto IL_00bb;
                    }
                    <>1__state = -1;
                    <maxSizeBytes>5__1 = 52428800;
                    Debug.WriteLine("LimitByWorkingSetSize Enter");
                    <>s__2 = input.GetEnumerator();
                    <>1__state = -3;
                    goto IL_00c3;
                    IL_00bb:
                    <process>5__3 = null;
                    goto IL_00c3;
                    IL_00c3:
                    if (<>s__2.MoveNext())
                    {
                        <process>5__3 = <>s__2.Current;
                        Debug.WriteLine("LimitByWorkingSetSize foreach");
                        if (<process>5__3.WorkingSet64 > <maxSizeBytes>5__1)
                        {
                            Debug.WriteLine("LimitByWorkingSetSize yield");
                            <>2__current = <process>5__3;
                            <>1__state = 1;
                            return true;
                        }
                        goto IL_00bb;
                    }
                    <>m__Finally1();
                    <>s__2 = null;
                    return false;
                }
                catch
                {
                    //try-fault
                    ((IDisposable)this).Dispose();
                    throw;
                }
            }

            bool IEnumerator.MoveNext()
            {
                //ILSpy generated this explicit interface implementation from .override directive in MoveNext
                return this.MoveNext();
            }

            private void <>m__Finally1()
            {
                <>1__state = -1;
                if (<>s__2 != null)
                {
                    <>s__2.Dispose();
                }
            }

            [DebuggerHidden]
            void IEnumerator.Reset()
            {
                throw new NotSupportedException();
            }

            [DebuggerHidden]
            IEnumerator<Process> IEnumerable<Process>.GetEnumerator()
            {
                <Execute>d__0 <Execute>d__;
                if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
                {
                    <>1__state = 0;
                    <Execute>d__ = this;
                }
                else
                {
                    <Execute>d__ = new <Execute>d__0(0);
                    <Execute>d__.<>4__this = <>4__this;
                }
                <Execute>d__.input = <>3__input;
                return <Execute>d__;
            }

            [DebuggerHidden]
            IEnumerator IEnumerable.GetEnumerator()
            {
                return ((IEnumerable<Process>)this).GetEnumerator();
            }
        }

        [IteratorStateMachine(typeof(<Execute>d__0))]
        public IEnumerable<Process> Execute(IEnumerable<Process> input)
        {
            <Execute>d__0 <Execute>d__ = new <Execute>d__0(-2);
            <Execute>d__.<>4__this = this;
            <Execute>d__.<>3__input = input;
            return <Execute>d__;
        }
    }
    internal class PrintProcessName : IOperation<Process>
    {
        [CompilerGenerated]
        private sealed class <Execute>d__0 : IEnumerable<Process>, IEnumerable, IEnumerator<Process>, IDisposable, IEnumerator
        {
            private int <>1__state;

            private Process <>2__current;

            private int <>l__initialThreadId;

            private IEnumerable<Process> input;

            public IEnumerable<Process> <>3__input;

            public PrintProcessName <>4__this;

            private IEnumerator<Process> <>s__1;

            private Process <process>5__2;

            Process IEnumerator<Process>.Current
            {
                [DebuggerHidden]
                get
                {
                    return <>2__current;
                }
            }

            object IEnumerator.Current
            {
                [DebuggerHidden]
                get
                {
                    return <>2__current;
                }
            }

            [DebuggerHidden]
            public <Execute>d__0(int <>1__state)
            {
                this.<>1__state = <>1__state;
                <>l__initialThreadId = Environment.CurrentManagedThreadId;
            }

            [DebuggerHidden]
            void IDisposable.Dispose()
            {
            }

            private bool MoveNext()
            {
                if (<>1__state != 0)
                {
                    return false;
                }
                <>1__state = -1;
                Debug.WriteLine("PrintProcessName Enter");
                <>s__1 = input.GetEnumerator();
                try
                {
                    while (<>s__1.MoveNext())
                    {
                        <process>5__2 = <>s__1.Current;
                        Debug.WriteLine("PrintProcessName  print");
                        Console.WriteLine(<process>5__2.ProcessName);
                        <process>5__2 = null;
                    }
                }
                finally
                {
                    if (<>s__1 != null)
                    {
                        <>s__1.Dispose();
                    }
                }
                <>s__1 = null;
                Debug.WriteLine("PrintProcessName break");
                return false;
            }

            bool IEnumerator.MoveNext()
            {
                //ILSpy generated this explicit interface implementation from .override directive in MoveNext
                return this.MoveNext();
            }

            [DebuggerHidden]
            void IEnumerator.Reset()
            {
                throw new NotSupportedException();
            }

            [DebuggerHidden]
            IEnumerator<Process> IEnumerable<Process>.GetEnumerator()
            {
                <Execute>d__0 <Execute>d__;
                if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
                {
                    <>1__state = 0;
                    <Execute>d__ = this;
                }
                else
                {
                    <Execute>d__ = new <Execute>d__0(0);
                    <Execute>d__.<>4__this = <>4__this;
                }
                <Execute>d__.input = <>3__input;
                return <Execute>d__;
            }

            [DebuggerHidden]
            IEnumerator IEnumerable.GetEnumerator()
            {
                return ((IEnumerable<Process>)this).GetEnumerator();
            }
        }

        [IteratorStateMachine(typeof(<Execute>d__0))]
        public IEnumerable<Process> Execute(IEnumerable<Process> input)
        {
            <Execute>d__0 <Execute>d__ = new <Execute>d__0(-2);
            <Execute>d__.<>4__this = this;
            <Execute>d__.<>3__input = input;
            return <Execute>d__;
        }
    }
    internal class Pipeline<T>
    {
        private readonly List<IOperation<T>> operations = new List<IOperation<T>>();

        public Pipeline<T> Register(IOperation<T> operation)
        {
            operations.Add(operation);
            return this;
        }

        public void Execute()
        {
            IEnumerable<T> enumerable = null;
            List<IOperation<T>>.Enumerator enumerator = operations.GetEnumerator();
            try
            {
                while (enumerator.MoveNext())
                {
                    IOperation<T> current = enumerator.Current;
                    enumerable = current.Execute(enumerable);
                }
            }
            finally
            {
                ((IDisposable)enumerator).Dispose();
            }
            IEnumerator<T> enumerator2 = enumerable.GetEnumerator();
            while (enumerator2.MoveNext())
            {
                int num = 0;
            }
        }
    }
}

为了我的钱,我可能会留下所有仅此而已:

Process.GetProcesses()
  .Where(p => p.BasePriority > 50*1024*1024)
  .Select(p => p.ProcessName)
  .ToList();

这里有一些关于 yield 的内容:

当一个方法使用 yield 返回某些内容时,可以返回到该方法并从我们离开的地方继续执行离开。看看这个不产生结果的方法:

int FibonacciSequence(){
  return 1;
  return 2;
  return 3;
  return 5;
}

当我们调用这个方法时,我们只会得到 1。第一次返回是硬停止;第二次返回是硬停止。我们可以调用它一百万次,但只有第一次返回才会起作用。所有其他代码完全无法访问。

现在让我们改变它,使其产生:

IEnumerable<int> FibonacciSequence(){
  yield return 1;
  yield return 2;
  yield return 3;
  yield return 5;
}

现在它是一个可枚举的,所以现在我们将其称为将枚举它的东西的一部分:

foreach(var v in FibonacciSequence())
  Console.WriteLine(v);

编译器做了很多事情来将您的 foreach 转换为获取枚举器并调用 movenext 的 while一遍又一遍,但关键是,当您枚举此生成方法时,它

  • 会向 foreach 循环返回
  • 1 1 被打印
  • movenext 被 foreach 无形地调用,这使得c# 在“return 1”之后返回方法,这次返回 2
  • 2 被打印
  • yield return 2 之后返回方法,return 3
  • 3 被打印
  • 回来,return 5
  • print 5
  • 返回,落在方法末尾,停止枚举

所以当我们让出时,就像它在该点的方法中放置了一个标记,返回到调用者,当我们返回到方法时(通过移动沿着 one 的迭代器),我们从我们停止的地方开始,而不是从方法的第一行开始

。您可以编写一个可以永远枚举的方法:

IEnumerable<int> FibonacciSequence(){
  int prevprev = 0;
  int prev = 1;

  while(true){
    int toReturn = prevprev + prev;
    prevprev = prev;
    prev = toReturn;
    yield return toReturn;
  }
}

每次达到 yield 时,C# 都会返回到具有新值的枚举代码。因为这是在一个循环中,所以它会继续生成斐波那契数列,直到它爆炸(如果您检查了数学,或者您填满了内存,或者如果您只是打印,则加法会导致溢出)永远走下去)。为了能够停止枚举,您需要从方法返回而不产生屈服(超出方法的末尾),或者执行yield break

I dont understand How and what is stored in private readonly List<IOperation> operations = new List<IOperation>(); ???

It's a List of IOperation<T>, in this case an instance of the GetAllProcesses, LimitByWorkingSetSize or PrintProcessName classes. All these classes implement the IOperation<T> interface and hence are capable of being treated as an IOperation<T>, and are permitted to be stored in the list.

as foreach has three execution

Yes but that just sets up the chain of calls for the LimitBy and PrintProcesses classes because their Executes are generators (feature yield) - they'll only be executed when they're enumerated. The current = operation.Execute(current); will execute the Execute of GetAll right away, because that doesn't yield anything (but it could be modified so it did) but running the code in PrintProcess, which leans on LimitBy, only happens when that MoveNext() occurs. PrintProcess traps control flow and doesn't yield anything while it's enumerating.

delegate which is executed when enumerator.MoveNext() is executed?

I suspect that's delving a bit deep into the mechanics of yield for this context (but you ask about it again below, so..)

OK, but we have Foreach, which is executed?

There are lots of foreaches in the code sample given. Executing the PrintProcess's Execute runs a foreach, which enumerates the output of the next method down in the chain (LimitBy's Execute) - which in itself also contains a foreach. If you single step it in the debugger with a breakpoint on the { under every foreach you'll see it jumping back and forth between PrintProcess and LimitBy; LimitBy is generating data on some loop passes that PrintProcess is enumerating. PrintProcesses doesn't yield anything to a further-up operation so control passes back and forth between these two until LimitBy has nothing left to give, at which point there will be no more things for PrintProcess to enumerate

So list "operations " should be ovverriden ... ?

I suspect that's a typo of overwritten. There isn't anything in the code that overwrites the operations list; it's current that's overwritten. It merely serves as a way of remembering what the output was last time so it can become an input this time on every pass of the loop. It wasn't strictly necessary to init it to a new List at the outset because the first Execute in this chain doesn't do anything with its input

How this "delegates" is stored before execution enumerator.MoveNext() is used. and at what it is used?

I think you're essentially asking how yield works; the short short version is that the compiler writes some classes for you that implement an enumerator that generates values based on the logic you used surrounding the yield keyword. The long answer is fairly horrific and not something you'd want to write yourself, which is why we're usually more than happy to let the compiler generate it and not look under the hood:

#define DEBUG
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
namespace ConsoleApp7net5
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            Pipeline<Process> pipeline = new Pipeline<Process>();
            pipeline.Register(new GetAllProcesses());
            pipeline.Register(new LimitByWorkingSetSize());
            pipeline.Register(new PrintProcessName());
            pipeline.Execute();
        }
    }
    internal interface IOperation<T>
    {
        IEnumerable<T> Execute(IEnumerable<T> input);
    }
    internal class GetAllProcesses : IOperation<Process>
    {
        public IEnumerable<Process> Execute(IEnumerable<Process> input)
        {
            Debug.WriteLine("GetAllProcesses Execute");
            return Process.GetProcesses();
        }
    }
    internal class LimitByWorkingSetSize : IOperation<Process>
    {
        [CompilerGenerated]
        private sealed class <Execute>d__0 : IEnumerable<Process>, IEnumerable, IEnumerator<Process>, IDisposable, IEnumerator
        {
            private int <>1__state;

            private Process <>2__current;

            private int <>l__initialThreadId;

            private IEnumerable<Process> input;

            public IEnumerable<Process> <>3__input;

            public LimitByWorkingSetSize <>4__this;

            private int <maxSizeBytes>5__1;

            private IEnumerator<Process> <>s__2;

            private Process <process>5__3;

            Process IEnumerator<Process>.Current
            {
                [DebuggerHidden]
                get
                {
                    return <>2__current;
                }
            }

            object IEnumerator.Current
            {
                [DebuggerHidden]
                get
                {
                    return <>2__current;
                }
            }

            [DebuggerHidden]
            public <Execute>d__0(int <>1__state)
            {
                this.<>1__state = <>1__state;
                <>l__initialThreadId = Environment.CurrentManagedThreadId;
            }

            [DebuggerHidden]
            void IDisposable.Dispose()
            {
                int num = <>1__state;
                if (num == -3 || num == 1)
                {
                    try
                    {
                    }
                    finally
                    {
                        <>m__Finally1();
                    }
                }
            }

            private bool MoveNext()
            {
                try
                {
                    int num = <>1__state;
                    if (num != 0)
                    {
                        if (num != 1)
                        {
                            return false;
                        }
                        <>1__state = -3;
                        goto IL_00bb;
                    }
                    <>1__state = -1;
                    <maxSizeBytes>5__1 = 52428800;
                    Debug.WriteLine("LimitByWorkingSetSize Enter");
                    <>s__2 = input.GetEnumerator();
                    <>1__state = -3;
                    goto IL_00c3;
                    IL_00bb:
                    <process>5__3 = null;
                    goto IL_00c3;
                    IL_00c3:
                    if (<>s__2.MoveNext())
                    {
                        <process>5__3 = <>s__2.Current;
                        Debug.WriteLine("LimitByWorkingSetSize foreach");
                        if (<process>5__3.WorkingSet64 > <maxSizeBytes>5__1)
                        {
                            Debug.WriteLine("LimitByWorkingSetSize yield");
                            <>2__current = <process>5__3;
                            <>1__state = 1;
                            return true;
                        }
                        goto IL_00bb;
                    }
                    <>m__Finally1();
                    <>s__2 = null;
                    return false;
                }
                catch
                {
                    //try-fault
                    ((IDisposable)this).Dispose();
                    throw;
                }
            }

            bool IEnumerator.MoveNext()
            {
                //ILSpy generated this explicit interface implementation from .override directive in MoveNext
                return this.MoveNext();
            }

            private void <>m__Finally1()
            {
                <>1__state = -1;
                if (<>s__2 != null)
                {
                    <>s__2.Dispose();
                }
            }

            [DebuggerHidden]
            void IEnumerator.Reset()
            {
                throw new NotSupportedException();
            }

            [DebuggerHidden]
            IEnumerator<Process> IEnumerable<Process>.GetEnumerator()
            {
                <Execute>d__0 <Execute>d__;
                if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
                {
                    <>1__state = 0;
                    <Execute>d__ = this;
                }
                else
                {
                    <Execute>d__ = new <Execute>d__0(0);
                    <Execute>d__.<>4__this = <>4__this;
                }
                <Execute>d__.input = <>3__input;
                return <Execute>d__;
            }

            [DebuggerHidden]
            IEnumerator IEnumerable.GetEnumerator()
            {
                return ((IEnumerable<Process>)this).GetEnumerator();
            }
        }

        [IteratorStateMachine(typeof(<Execute>d__0))]
        public IEnumerable<Process> Execute(IEnumerable<Process> input)
        {
            <Execute>d__0 <Execute>d__ = new <Execute>d__0(-2);
            <Execute>d__.<>4__this = this;
            <Execute>d__.<>3__input = input;
            return <Execute>d__;
        }
    }
    internal class PrintProcessName : IOperation<Process>
    {
        [CompilerGenerated]
        private sealed class <Execute>d__0 : IEnumerable<Process>, IEnumerable, IEnumerator<Process>, IDisposable, IEnumerator
        {
            private int <>1__state;

            private Process <>2__current;

            private int <>l__initialThreadId;

            private IEnumerable<Process> input;

            public IEnumerable<Process> <>3__input;

            public PrintProcessName <>4__this;

            private IEnumerator<Process> <>s__1;

            private Process <process>5__2;

            Process IEnumerator<Process>.Current
            {
                [DebuggerHidden]
                get
                {
                    return <>2__current;
                }
            }

            object IEnumerator.Current
            {
                [DebuggerHidden]
                get
                {
                    return <>2__current;
                }
            }

            [DebuggerHidden]
            public <Execute>d__0(int <>1__state)
            {
                this.<>1__state = <>1__state;
                <>l__initialThreadId = Environment.CurrentManagedThreadId;
            }

            [DebuggerHidden]
            void IDisposable.Dispose()
            {
            }

            private bool MoveNext()
            {
                if (<>1__state != 0)
                {
                    return false;
                }
                <>1__state = -1;
                Debug.WriteLine("PrintProcessName Enter");
                <>s__1 = input.GetEnumerator();
                try
                {
                    while (<>s__1.MoveNext())
                    {
                        <process>5__2 = <>s__1.Current;
                        Debug.WriteLine("PrintProcessName  print");
                        Console.WriteLine(<process>5__2.ProcessName);
                        <process>5__2 = null;
                    }
                }
                finally
                {
                    if (<>s__1 != null)
                    {
                        <>s__1.Dispose();
                    }
                }
                <>s__1 = null;
                Debug.WriteLine("PrintProcessName break");
                return false;
            }

            bool IEnumerator.MoveNext()
            {
                //ILSpy generated this explicit interface implementation from .override directive in MoveNext
                return this.MoveNext();
            }

            [DebuggerHidden]
            void IEnumerator.Reset()
            {
                throw new NotSupportedException();
            }

            [DebuggerHidden]
            IEnumerator<Process> IEnumerable<Process>.GetEnumerator()
            {
                <Execute>d__0 <Execute>d__;
                if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
                {
                    <>1__state = 0;
                    <Execute>d__ = this;
                }
                else
                {
                    <Execute>d__ = new <Execute>d__0(0);
                    <Execute>d__.<>4__this = <>4__this;
                }
                <Execute>d__.input = <>3__input;
                return <Execute>d__;
            }

            [DebuggerHidden]
            IEnumerator IEnumerable.GetEnumerator()
            {
                return ((IEnumerable<Process>)this).GetEnumerator();
            }
        }

        [IteratorStateMachine(typeof(<Execute>d__0))]
        public IEnumerable<Process> Execute(IEnumerable<Process> input)
        {
            <Execute>d__0 <Execute>d__ = new <Execute>d__0(-2);
            <Execute>d__.<>4__this = this;
            <Execute>d__.<>3__input = input;
            return <Execute>d__;
        }
    }
    internal class Pipeline<T>
    {
        private readonly List<IOperation<T>> operations = new List<IOperation<T>>();

        public Pipeline<T> Register(IOperation<T> operation)
        {
            operations.Add(operation);
            return this;
        }

        public void Execute()
        {
            IEnumerable<T> enumerable = null;
            List<IOperation<T>>.Enumerator enumerator = operations.GetEnumerator();
            try
            {
                while (enumerator.MoveNext())
                {
                    IOperation<T> current = enumerator.Current;
                    enumerable = current.Execute(enumerable);
                }
            }
            finally
            {
                ((IDisposable)enumerator).Dispose();
            }
            IEnumerator<T> enumerator2 = enumerable.GetEnumerator();
            while (enumerator2.MoveNext())
            {
                int num = 0;
            }
        }
    }
}

And for my money I'd probably leave all this alone and just do:

Process.GetProcesses()
  .Where(p => p.BasePriority > 50*1024*1024)
  .Select(p => p.ProcessName)
  .ToList();

Here's a bit on yield:

When a method returns something using yield, it is possible to get back into the method and carry on from where we left off. Look at this method that doesn't yield:

int FibonacciSequence(){
  return 1;
  return 2;
  return 3;
  return 5;
}

When we call this, we'll only ever get 1. The first return is a hard stop; we could call it a million times and only the first return ever does anything. All the other code is totally unreachable.

Now let's change it so it yields:

IEnumerable<int> FibonacciSequence(){
  yield return 1;
  yield return 2;
  yield return 3;
  yield return 5;
}

It's a enumerable now, so now we call it as part of something that will enumerate over it:

foreach(var v in FibonacciSequence())
  Console.WriteLine(v);

There's a bunch of stuff the compiler does to transform your foreach into a while that gets an enumerator and calls movenext over and over but the crux of it is, when you enumerate over this yielding method it

  • returns 1 to the foreach loop
  • 1 is printed
  • movenext is called invisibly by the foreach, which makes c# go back into the method just after the "return 1" and this time it returns 2
  • 2 is printed
  • go back into the method after the yield return 2, return 3
  • 3 is printed
  • back in, return 5
  • print 5
  • back in, fall out of the end of the method, stopping the enumeration

So when we yield, it's like it places a marker in the method at that point, goes back to the caller, and when we come back into the method (by moving the iterator along one), we start at the marker from where we left off, rather than from the first line of the method

You don't have to hard code your yields; you can write a method that you can enumerate forever:

IEnumerable<int> FibonacciSequence(){
  int prevprev = 0;
  int prev = 1;

  while(true){
    int toReturn = prevprev + prev;
    prevprev = prev;
    prev = toReturn;
    yield return toReturn;
  }
}

Every time it hits yield, C# goes back to the enumerating code with the new value. Because this is in a loop it'll just keep generating Fibonacci til it blows up (the addition results in an overflow if you have checked math on, or you fill up your memory.. or if you're just printing, it'll go forever). To be able to stop enumerating you either need to return from the method without yielding(fall out of the end of the method), or do a yield break

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文