C#:使 class 在 foreach 中可用

C#: making a class usable in foreach

我在这方面遇到了一些问题: 我必须在 C# 中创建一个 PrimeCollection class 来实现 IEnumerable 接口并动态生成素数集合。

所以如果我写这样的测试:

static void Main(string[] args) {
    PrimeCollection pc = new PrimeCollection();
    foreach (int p in pc)
        Console.WriteLine(p);
}

它应该生成素数,直到达到 int32 限制。

到目前为止我有这个:

class PrimeCollection {
    public IEnumerable<int> Primes() {
        var ints = Enumerable.Range(2, Int32.MaxValue - 1);
        return ints.Where(x => !ints.TakeWhile(y => y < Math.Sqrt(x)).Any(y => x % y == 0));
    }
}

但是要进行生成,我需要这样调用它:

static void Main(string[] args) {
    PrimeCollection pc = new PrimeCollection();
    foreach (int p in pc.Primes())
        Console.WriteLine(p);
}

我假设我需要使 class IEnumerable,而不是方法,但是我不知道如何即时生成数字。

根本没有理由拥有可实例化的 class。你没有持有状态。

public static class Prime
{
    public static IEnumerable<int> Values() 
    {
        var ints = Enumerable.Range(2, Int32.MaxValue - 1);
        return ints.Where(x => !ints.TakeWhile(y => y < Math.Sqrt(x)).Any(y => x % y == 0));
    }
}

那么你可以这样使用它:

static void Main(string[] args) 
{
    foreach (int p in Prime.Values())
        Console.WriteLine(p);
}

如果您想专门创建您的自定义 primes-enumerable,您可以将其定义为现有 linq 查询的包装器。像这样:

public class PrimesEnumerable : IEnumerable<int> {
    public PrimesEnumerable() {
        var ints = Enumerable.Range(2, Int32.MaxValue - 1);
        _internalEnumerable = ints.Where(x => !ints.TakeWhile(y => y*y<=x).Any(y => x % y == 0));
    }
    public readonly IEnumerable<int> _internalEnumerable;

    public IEnumerator<int> GetEnumerator() {
        return _internalEnumerable.GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
        return _internalEnumerable.GetEnumerator();
    }
}

现在你可以 foreach 了:

var primes = new PrimesEnumerable();

int i = 0;
foreach (var prime in primes) {
    if (i == 10)
        break;

    Console.WriteLine(prime);
    i++;
}
Console.ReadLine();

注意:一定要修复@CarstenKönig 所说的错误。

你的意思是这样的?

class Program
{
    static void Main(string[] args)
    {
        foreach(var prime in new PrimeCollection())
        {
            Console.WriteLine(prime);
        }
        Console.Read();
    }
}

class PrimeCollection : IEnumerable
{
    public IEnumerator GetEnumerator()
    {
        var ints = Enumerable.Range(2, Int32.MaxValue - 1);
        return ints.Where(x => !ints.TakeWhile(y => y < Math.Sqrt(x)).Any(y => x % y == 0)).GetEnumerator();
    }
}