C#“生成器"方法 [英] C# "Generator" Method

查看:89
本文介绍了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#“生成器"方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆