自定义枚举器的需求点

发布于 2024-08-08 14:05:44 字数 1514 浏览 1 评论 0原文

阅读帖子时,给出了一些要点没有示例

要实现 IEnumerable / IEnumerable,您必须提供一个枚举器:

•如果该类“包装”另一个集合,则通过返回包装集合的枚举器.

•通过使用yield return 的迭代器。

•通过实例化您自己的 IEnumerator/IEnumerator 实现

(我的幼稚头脑将其解释为)

(Point 1)

    If the class is "wrapping" another collection, by returning the
wrapped collection's enumerator.

这意味着..

class  StringCollections
{

 //A class is wrapping another collection
  string[]  names=new string {“Jon Skeet”,”Hamish Smith”,
                  ”Marc Gravell”,”Jrista”,”Joren”};

//by returning the wrapped collection’s enumerator

 public IEnumerator GetEnumerator( )
  {
      // What should I return here ?
       //like the following ?
        yield return names[0];
        yield return names[1];
        yield return names[2];
      ....

       (or)
        foreach(string str in names)
        {
            yield return str;
         }                  

  }

}

(Point 2)

•Via an iterator using yield return.(This point was well explained 
 by Marc Gravell)

Point 3

By instantiating your own IEnumerator/IEnumerator<T> implementation*

这里第3点代表什么?,因为没有例子,我没有得到那个。 这是否意味着,我可以构建自定义枚举器..(对吗?)。我的问题是,预构建枚举器/枚举器何时足够(作为初学者,我不应该盲目确认这一点) 迭代为什么我应该照顾定制的?一个很好的例子会澄清我的疑问。

感谢您阅读这篇冗长的故事和友善的回复。

When reading a post some points were given without example :

To implement IEnumerable / IEnumerable, you must provide an enumerator :

•If the class is "wrapping" another collection, by returning the wrapped collection's enumerator.

•Via an iterator using yield return.

•By instantiating your own IEnumerator/IEnumerator implementation

(My baby mind interprets it as)

(Point 1)

    If the class is "wrapping" another collection, by returning the
wrapped collection's enumerator.

Will it mean ..

class  StringCollections
{

 //A class is wrapping another collection
  string[]  names=new string {“Jon Skeet”,”Hamish Smith”,
                  ”Marc Gravell”,”Jrista”,”Joren”};

//by returning the wrapped collection’s enumerator

 public IEnumerator GetEnumerator( )
  {
      // What should I return here ?
       //like the following ?
        yield return names[0];
        yield return names[1];
        yield return names[2];
      ....

       (or)
        foreach(string str in names)
        {
            yield return str;
         }                  

  }

}

(Point 2)

•Via an iterator using yield return.(This point was well explained 
 by Marc Gravell)

Point 3

By instantiating your own IEnumerator/IEnumerator<T> implementation*

What does point 3 represent here?,since no example,i did not get that one.
Does it mean,i can build custom enumerator ..(right?).My question here is when prebuild enumerator/enumerators are sufficient (as a beginner i should not blindly confirm this) for
iterations why should i look after the custom one ?Nice example will clarify my doubt.

Thanks for reading this long winded story and kind response.

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

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

发布评论

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

评论(4

清欢 2024-08-15 14:05:45

(point 1) 您可以将 GetEnumerator 的调用链接到其他集合枚举器:

public class PrimeNumbers : IEnumerable
{
    public IEnumerator GetEnumerator()
    {
        var primes = new List<int> { 2, 3, 5, 7, 11 };
        return primes.GetEnumerator();
    }
}

(point 2) 类似于例如在您的代码中

public IEnumerator GetEnumerator()
{
    var primes = new List<int> { 2, 3, 5, 7, 11 };
    foreach (var number in primes)
    {
        yield return number;
    }
}

或将枚举器与逻辑一起放置:

public class PrimeNumbers : IEnumerable
{
    public IEnumerator GetEnumerator()
    {
        for(int i=2; ;i++)
        {
            if(IsPrime(i))
            {
                yield return i;
            }
        }
    }
}

(Point 3) 您想要实现自己的枚举器的情况并不多,但例如您可以寻找一个无限的值集,例如质数:

public class PrimeNumbers : IEnumerable
{
    public IEnumerator GetEnumerator()
    {
        return new MyEnumerator();
    }
}

public class MyEnumerator : IEnumerator
{
    private int lastPrimeNumber = 1;

    public bool MoveNext()
    {
        lastPrimeNumber = /* some logic that find the next prime */;
        return true; // There is always next prime
    }

    public void Reset()
    {
        lastPrimeNumber = 1;
    }

    public object Current
    {
        get { return lastPrimeNumber; }
    }
}

使用示例可以是:

public void PrintAllPrimes()
{
    var numbers = new PrimeNumbers();

    // This will never end but it'll print all primes until my PC crash
    foreach (var number in numbers)
    {
        Console.WriteLine(number);
    }
}

优点和优点我能想到的缺点:

  • 第 1 点:这是枚举项目的最简单方法,但它需要
    提前知道所有项目
  • 第 2 点:当枚举中有一些逻辑时,它是可读的,它是
    也很懒所以没必要
    计算一个项目,直到它实际上为止
    请求的
  • 第 3 点:重用最简单,但可读性较差(计算 item
    在 MoveNext 但实际上从
    当前财产)。

(point 1) You can chain the call of GetEnumerator to other collection enumerator:

public class PrimeNumbers : IEnumerable
{
    public IEnumerator GetEnumerator()
    {
        var primes = new List<int> { 2, 3, 5, 7, 11 };
        return primes.GetEnumerator();
    }
}

(point 2) Similar to example in your code

public IEnumerator GetEnumerator()
{
    var primes = new List<int> { 2, 3, 5, 7, 11 };
    foreach (var number in primes)
    {
        yield return number;
    }
}

Or place enumerator with logic:

public class PrimeNumbers : IEnumerable
{
    public IEnumerator GetEnumerator()
    {
        for(int i=2; ;i++)
        {
            if(IsPrime(i))
            {
                yield return i;
            }
        }
    }
}

(Point 3) There are not many cases where you want to implement your own Enumerator, but for example you can look for an infinite set of values, e.g. prime numbers:

public class PrimeNumbers : IEnumerable
{
    public IEnumerator GetEnumerator()
    {
        return new MyEnumerator();
    }
}

public class MyEnumerator : IEnumerator
{
    private int lastPrimeNumber = 1;

    public bool MoveNext()
    {
        lastPrimeNumber = /* some logic that find the next prime */;
        return true; // There is always next prime
    }

    public void Reset()
    {
        lastPrimeNumber = 1;
    }

    public object Current
    {
        get { return lastPrimeNumber; }
    }
}

A usage example could be:

public void PrintAllPrimes()
{
    var numbers = new PrimeNumbers();

    // This will never end but it'll print all primes until my PC crash
    foreach (var number in numbers)
    {
        Console.WriteLine(number);
    }
}

Pros & Cons I can think of:

  • Point 1: It's the simplest way to enumerate items but it requires
    knowing all items in advance
  • Point 2: It's readable when there's some logic in the enumeration, it's
    also lazy so there is no need to
    compute an item until it's actually
    requested
  • Point 3: It's simplest to reuse but it is less readable (calculate item
    in MoveNext but actually return from
    Current property).
再可℃爱ぅ一点好了 2024-08-15 14:05:45

这是一个示例:(注意:这是简化的,不是线程安全的示例)

public class PersonCollection : IEnumerable
{
    private ArrayList alPers = new ArrayList();
    public IEnumerator GetEnumerator() { return new myTypeEnumerator(this); }
    public class myTypeEnumerator : IEnumerator
    {
        int nIndex;
        PersonCollection pers;
        private int count { get { return pers.alPers.Count; } }
        public myTypeEnumerator(PersonCollection myTypes) 
         { pers = myTypes; nIndex = -1; }
        public bool MoveNext() { return nIndex <= count && ++nIndex < count; }
        // MovePrev() not strictly required
        public bool MovePrev() { return (nIndex > -1 && --nIndex > 0 ); }
        public object Current { get { return (pers[nIndex]); } }
        public void Reset() { nIndex = -1; }
    }
}

编辑:修复下面由 @Joren 提出的与 Move Previous 将索引值低于 -1 相关的问题。当框架作为 foreach 实现的一部分调用时,MoveNext() 不需要此修复,因为在这种情况下,如果 MoveNext() 返回 false,枚举器实例将终止。但是,如果客户端手动调用 MoveNext(),枚举器将不会终止,因此还需要修复。

另请注意:如何实现这个东西内部的细节取决于你,并且取决于它内部如何管理状态。例如,如果保存引用的 iunternal“bucket”是一个链接列表,而不是 ArrayList,则 MoveNext() 可以通过仅更改 Current 字段以指向旧当前的 nextItem 属性来实现...

Here's an example: (NOTE: This is simplified, not thread safe example)

public class PersonCollection : IEnumerable
{
    private ArrayList alPers = new ArrayList();
    public IEnumerator GetEnumerator() { return new myTypeEnumerator(this); }
    public class myTypeEnumerator : IEnumerator
    {
        int nIndex;
        PersonCollection pers;
        private int count { get { return pers.alPers.Count; } }
        public myTypeEnumerator(PersonCollection myTypes) 
         { pers = myTypes; nIndex = -1; }
        public bool MoveNext() { return nIndex <= count && ++nIndex < count; }
        // MovePrev() not strictly required
        public bool MovePrev() { return (nIndex > -1 && --nIndex > 0 ); }
        public object Current { get { return (pers[nIndex]); } }
        public void Reset() { nIndex = -1; }
    }
}

EDIT: to fix issue raised by @Joren below related to Move Previous taking index value below -1. When called by framework as part of foreach implementation, MoveNext() would not need this fix because in that case if MoveNext() returns false, enumerator instance will terminate. However, if client manually calls MoveNext(), enumerator would not terminate, so it also needs the fix.

Also NOTE: how you implement the details inside this thing is up to you, and will be dependant on how it internally manages state. For example if the iunternal "bucket" that holds the references was a linked list, instead of an ArrayList, then the MoveNext() might be implemented by just changing a Current field to point to the old current's nextItem property...

泡沫很甜 2024-08-15 14:05:45

您所说的 1 实际上适用于 2。

对于 1,它更像是

public IEnumerator GetEnumerator() {
    return names.GetEnumerator();
}

对于第 3 点,这意味着让 GetEnumerator 做一些实际的工作:手动为您定义的集合实现一个 Enumerator。

What you said for 1 would actually be for 2.

For 1, it'd be more like

public IEnumerator GetEnumerator() {
    return names.GetEnumerator();
}

For point 3, it'd mean to make GetEnumerator do some real work: Implementing, by hand, an Enumerator for the collection you defined.

淡淡の花香 2024-08-15 14:05:45

“如果该类正在“包装”另一个集合,则通过返回包装的集合的枚举器”意味着:

class StringCollections{
    //A class is wrapping another collection
    string[] names=new string {“Jon Skeet”,”Hamish Smith”,
                                ”Marc Gravell”,”Jrista”,”Joren”};
    public IEnumerator GetEnumerator() { return names.GetEnumerator(); }
}

"If the class is "wrapping" another collection, by returning thewrapped collection's enumerator" means:

class StringCollections{
    //A class is wrapping another collection
    string[] names=new string {“Jon Skeet”,”Hamish Smith”,
                                ”Marc Gravell”,”Jrista”,”Joren”};
    public IEnumerator GetEnumerator() { return names.GetEnumerator(); }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文