C#“生成器"方法

编程入门 行业动态 更新时间:2024-10-27 20:34:23
本文介绍了C#“生成器"方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我来自Python世界,正在尝试用C#创建一个生成器"方法.我正在按特定缓冲区大小的块来解析文件,并且只想一次读取和存储下一个块,并在foreach循环中产生它.这是我到目前为止(简化的概念证明):

I come from the world of Python and am trying to create a "generator" method in C#. I'm parsing a file in chunks of a specific buffer size, and only want to read and store the next chunk one at a time and yield it in a foreach loop. Here's what I have so far (simplified proof of concept):

class Page { public uint StartOffset { get; set; } private uint currentOffset = 0; public Page(MyClass c, uint pageNumber) { uint StartOffset = pageNumber * c.myPageSize; if (StartOffset < c.myLength) currentOffset = StartOffset; else throw new ArgumentOutOfRangeException("Page offset exceeds end of file"); while (currentOffset < c.myLength && currentOffset < (StartOffset + c.myPageSize)) // read data from page and populate members (not shown for MWE purposes) . . . } } class MyClass { public uint myLength { get; set; } public uint myPageSize { get; set; } public IEnumerator<Page> GetEnumerator() { for (uint i = 1; i < this.myLength; i++) { // start count at 1 to skip first page Page p = new Page(this, i); try { yield return p; } catch (ArgumentOutOfRangeException) { // end of available pages, how to signal calling foreach loop? } } } }

我知道这不是完美的,因为这是一个最低限度的工作示例(我不允许公开设置许多这些属性,但是为了保持简单性,我不想键入私有成员和属性).

I know this is not perfect since it is a minimum working example (I don't allow many of these properties to be set publicly, but for keeping this simple I don't want to type private members and properties).

但是,我的主要问题是如何让调用者使用foreach语句在MyClass上循环,从而知道没有其他项目可以循环了?我是否抛出异常以指示还没有元素?

However, my main question is how do I let the caller looping over MyClass with a foreach statement know that there are no more items left to loop through? Is there an exception I throw to indicate there are no elements left?

推荐答案

如注释中所述,您应该使用IEnumerable<T>而不是IEnumerator<T>.枚举器是用于枚举某些内容的技术对象.在许多情况下,这些东西是可以枚举的.

As mentioned in the comments, you should use IEnumerable<T> instead of IEnumerator<T>. The enumerator is the technical object that is being used to enumerate over something. That something—in many cases–is an enumerable.

C#具有处理枚举的特殊功能.最显着的是,您可以将foreach循环用于可枚举(但不能使用枚举器;即使该循环实际上使用了可枚举的枚举器).另外,可枚举允许您使用 LINQ ,这使得它更容易实现消费.

C# has special abilities to deal with enumerables. Most prominently, you can use a foreach loop with an enumerable (but not an enumerator; even though the loop actually uses the enumerator of the enumerable). Also, enumerables allow you to use LINQ which makes it even more easier to consume.

所以您应该像这样更改班级:

So you should change your class like this:

class MyClass { public uint myLength { get; set; } public uint myPageSize { get; set; } # note the modified signature public IEnumerable<Page> GetPages() { for (uint i = 1; i < this.myLength; i++) { Page p; try { p = new Page(this, i); } catch (ArgumentOutOfRangeException) { yield break; } yield return p; } } }

最后,您可以像这样使用它:

In the end, this allows you to use it like this:

var obj = new MyClass(); foreach (var page in obj.GetPages()) { // do whatever } // or even using LINQ var pageOffsets = obj.GetPages().Select(p => p.currentOffset).ToList();

当然,您还应该将方法的 name 更改为有意义的名称.如果您要返回页面,则GetPages可能是朝着正确方向迈出的良好第一步.名称GetEnumerator是为实现IEnumerable的类型保留的,其中GetEnumerator方法应该返回对象表示的集合的枚举数.

Of course, you should also change the name of the method to something meaningful. If you’re returning pages, GetPages is maybe a good first step in the right direction. The name GetEnumerator is kind of reserved for types implementing IEnumerable, where the GetEnumerator method is supposed to return an enumerator of the collection the object represents.

更多推荐

C#“生成器"方法

本文发布于:2023-11-10 09:18:01,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1574975.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:生成器   方法   quot

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!