Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何创建字符串或整数的枚举器/生成器?_C#_.net_Collections_Ienumerable - Fatal编程技术网

C# 如何创建字符串或整数的枚举器/生成器?

C# 如何创建字符串或整数的枚举器/生成器?,c#,.net,collections,ienumerable,C#,.net,Collections,Ienumerable,我想要一个枚举器/生成器,每当我调用say GetNext时,它总是向我提供下一个值?这可能吗 Examples: myStringEnumerator.GetNext() -> returns "Identifier01.xml" myStringEnumerator.GetNext() -> returns "Identifier02.xml" myStringEnumerator.GetNext() -> returns "Identifier03.xml"

我想要一个枚举器/生成器,每当我调用say GetNext时,它总是向我提供下一个值?这可能吗

Examples:

myStringEnumerator.GetNext()
  -> returns "Identifier01.xml"
myStringEnumerator.GetNext()
  -> returns "Identifier02.xml"
myStringEnumerator.GetNext()
  -> returns "Identifier03.xml"
myStringEnumerator.GetNext()
  -> returns "Identifier04.xml"
myStringEnumerator.GetNext()
  -> returns "Identifier05.xml"
...

evenNumberGenerator.GetNext()
  -> returns 0
evenNumberGenerator.GetNext()
  -> returns 2
evenNumberGenerator.GetNext()
  -> returns 4
evenNumberGenerator.GetNext()
  -> returns 6
evenNumberGenerator.GetNext()
  -> returns 8
evenNumberGenerator.GetNext()
  -> returns 10
...
我不会在1个地方迭代它,而是在许多地方和非常不同的时间迭代

我该如何以最优雅的方式做到这一点?如果它也很快,那也很好。

它是.net的一部分

IEnumerable<T>.GetEnumerator()
我相信你可以自己解决剩下的问题

如果您确实需要“无限”枚举,那么使用yield语句也可能是一个很好的选择,但是字符串的格式使我认为99是最大值,术语“枚举器”在这里有点误导,因为这是一种有开始和结束的特定序列类型。在您的例子中,您并不是每次都枚举任何内容,而是无限期地前进到下一个值。听起来是一个很好的单亲家庭用法:

class NextNumberGenerator
{
    private static NextNumberGenerator instance = new NextNumberGenerator();

    public static NextNumberGenerator Current
    {
        get { return instance; }
    }

    private int currentNumber = 0;

    public int GetNext()
    {
        return ++currentNumber;
    }

    public int GetNextEven()
    {
        currentNumber++;
        return (currentNumber % 2 == 0) ? currentNumber : ++currentNumber;
    }

    public int GetNextOdd()
    {
        currentNumber++;
        return (currentNumber % 2 != 0) ? currentNumber : ++currentNumber;
    }
}
用作:

int value = NextNumberGenerator.Current.GetNext();

编辑:一些评论指出,使用IEnumerable是完全可能的。然而,我认为这是对IEnumerable的误用,因为这个例子和这个例子在某些方面看起来很相似,但并不相同。使用一个非常具体、有目的的界面,因为它所做的多项事情中有一项与您所需要的事情相似(不相同),它会反过来伤害您。

最简单的方法是使用。例如:

public static IEnumerator<int> GetNumbers() {
    for (int i = 0; i < 25; i += 3)
        yield return i;
}

//You can also do it without a loop, like this:
public static IEnumerator<string> GetNames() {
    yield return "Identifier01.xml";
    yield return "Identifier02.xml";
    yield return "Identifier03.xml";
    yield return "Identifier04.xml";
    yield return "Identifier05.xml";
}
公共静态IEnumerator GetNumbers(){
对于(int i=0;i<25;i+=3)
收益率i;
}
//您也可以在不使用循环的情况下执行此操作,如下所示:
公共静态IEnumerator GetNames(){
产生返回“Identifier01.xml”;
产生返回“Identifier02.xml”;
产生返回“Identifier03.xml”;
产生返回“Identifier04.xml”;
收益返回“Identifier05.xml”;
}
您还可以返回一个而不是一个,而无需更改除返回类型以外的任何内容。IEnumerable是一个创建IEnumerator的对象,IEnumerator在其上枚举,可用于
foreach
循环。请注意,如果返回IEnumerable,则每次(由不同的枚举器)枚举一个IEnumerable时,代码都将再次运行


要在不同的方法中使用它,可以在静态字段中共享IEnumerator

public IEnumerable<string> GetFileNames()
{
    for (int i = 1; i <= 99; i++)
    {
        yield return string.Format("Identifier{0:00}.xml", i);
    }
}
要在没有foreach的情况下使用它,您可以这样做:

IEnumerator<string> names = GetFileNames().GetEnumerator();
names.MoveNext();
string name1 = names.Current;
names.MoveNext();
string name2 = names.Current;
// etc, etc.
static class FileNames {
    static int nextNumber;

    public static string NextName() {
        nextNumber++;
        return String.Format(CultureInfo.InvariantCulture, "Indentifier{0:00}.xml", nextNumber);
    }
}
IEnumerator name=getFileName().GetEnumerator();
names.MoveNext();
string name1=names.Current;
names.MoveNext();
string name2=names.Current;
//等等等等。
要满足Rex M:

IEnumerator<string> filenames = GetFileNames().GetEnumerator();
while (filenames.MoveNext())
{
    if (!File.Exists(filenames.Current))
        break;
}

while(haveFilesToWrite)
{
    // Use filenames.Current to open a file and write it
    filenames.MoveNext();
}
IEnumerator filenames=GetFileNames().GetEnumerator();
while(filename.MoveNext())
{
如果(!File.Exists(filenames.Current))
打破
}
while(haveFilesToWrite)
{
//使用filenames.Current打开并写入文件
filenames.MoveNext();
}

枚举数很好,因为您可以在foreach循环中使用它们,并使用LINQ以各种有趣的方式使用它们

下面是一个枚举员做你在原始问题中提到的事情的例子:

static class MyEnumerators 
{
    IEnumerable <string> NumberedStringEnumerator (string format, int start, int count)
    {
        for ( int n = 0; n < count; ++n )
            yield return string.Format (format, start + n);
    }
}

static void Main ()
{
    foreach ( string s in NumberedStringEnumerator ("Identifier{0:2D}.xml", 1, 5) )
        Console.WriteLine (s);
}

听起来您实际上想要一个静态函数,如下所示:

IEnumerator<string> names = GetFileNames().GetEnumerator();
names.MoveNext();
string name1 = names.Current;
names.MoveNext();
string name2 = names.Current;
// etc, etc.
static class FileNames {
    static int nextNumber;

    public static string NextName() {
        nextNumber++;
        return String.Format(CultureInfo.InvariantCulture, "Indentifier{0:00}.xml", nextNumber);
    }
}
请注意,这将从1开始,而不是从零开始。要使其以零开始,请将
nextNumber
初始化为-1编辑:或者,删除第一行(
nextNumber++
),并将第二行中的参数更改为
++nextNumber


而且,这并不是说它不是线程安全的。如果要在多个线程上调用它,请使用。

像这样简单的事情怎么样

public partial class Form1 : Form
{
    private void Form1_Load(object sender, EventArgs e)
    {
        myGen myStringEnumerator = new myGen(myGen.wanted.nextNum);
        myGen evenNumberGenerator = new myGen(myGen.wanted.EvenNum);

        for (int i = 0; i <= 5; i++)
        {
            MessageBox.Show(string.Format("Identifier{0}.xml", myStringEnumerator.GetNext().ToString("00")));
        }

        for (int i = 0; i <= 5; i++)
        {
            MessageBox.Show(evenNumberGenerator.GetNext().ToString());
        }
    }
}

public class myGen
{
    private int num = 0;
    public enum wanted
    {
        nextNum,
        EvenNum,
        OddNum
    }
    private wanted _wanted;

    public myGen(wanted wanted)
    {
        _wanted = wanted;
    }

    public int GetNext()
    {
        num++;
        if (_wanted == wanted.EvenNum)
        {
            if (num % 2 == 1)
            {
                num++;
            }
        }
        else if (_wanted == wanted.OddNum)
        {
            if (num % 2 == 0)
            {
                num++;
            }
        }
        return num;
    }
}
公共部分类表单1:表单
{
私有void Form1\u加载(对象发送方、事件参数e)
{
myGen myStringEnumerator=新的myGen(myGen.wanted.nextNum);
myGen evenNumberGenerator=新的myGen(myGen.wanted.EvenNum);

对于(int i=0;我很感谢,但是如何生成我上面发布的那些值呢?我认为OP使用的“枚举器”一词有点误导。请看我的答案。感谢spender,是的,可能是字符串,但对于偶数,我希望它是无限的,但您的回答很好。对于偶数的“无限”供应(无论如何,最大值为Int32!):Enumerable.Range(0,Int32.MaxValue)。其中(n=>n%2==0)。GetEnumerator()。如果确实需要,请使用Int64。如果确实需要“无限”您需要从某个地方获得BigInteger实现并编写迭代器方法。如果这是您的意思,Range不会预先生成大量集合。在这种情况下,Range的内存使用量将是最小的。在生成的IEnumerable上调用ToList或ToArray可能会有问题。谢谢,因此我不需要实现IEnumerable,对吗?我可以吗?如果可以的话,这会使单例变短,但不确定是否可行。所以我可以说yield return String.Format(“Identifier{0}.xml”,val++);这主意不错,但为什么不删除“current”部分并直接在getnext中使用它呢?所以NextNumber Generator.getnext()@Rex:我完全不同意。
IEnumerable
不需要在
foreach
中使用,也不需要无限,即使在这种情况下,如果你在处理完序列后小心使用
break
。Rex:也许我误解了你,但我不确定Matthew的评论“如何绕过IEnumerable模式的一部分”IEnumerable不要求结束,无限枚举数非常有用,因为它们允许调用代码施加自己的终止条件,而不是将其烘焙到枚举数中。例如,foreach(AllPrimes()中的BigInteger p)。其中(p@Rex我不同意,无限集仍然是合法集,可以合法地迭代。你比我快了30秒!谢谢Matthew。我如何在多个地方使用它?比如GetFileNames()。接下来在method0中,稍后在method1 GetFileNames()中).Next,然后是method2内部,等等?代码的不同部分要求下一个元素。我不确定这是否是个好主意-为每个迭代执行n个I/O操作?@Rex:我假设将使用第一个示例
static class FileNames {
    static int nextNumber;

    public static string NextName() {
        nextNumber++;
        return String.Format(CultureInfo.InvariantCulture, "Indentifier{0:00}.xml", nextNumber);
    }
}
public partial class Form1 : Form
{
    private void Form1_Load(object sender, EventArgs e)
    {
        myGen myStringEnumerator = new myGen(myGen.wanted.nextNum);
        myGen evenNumberGenerator = new myGen(myGen.wanted.EvenNum);

        for (int i = 0; i <= 5; i++)
        {
            MessageBox.Show(string.Format("Identifier{0}.xml", myStringEnumerator.GetNext().ToString("00")));
        }

        for (int i = 0; i <= 5; i++)
        {
            MessageBox.Show(evenNumberGenerator.GetNext().ToString());
        }
    }
}

public class myGen
{
    private int num = 0;
    public enum wanted
    {
        nextNum,
        EvenNum,
        OddNum
    }
    private wanted _wanted;

    public myGen(wanted wanted)
    {
        _wanted = wanted;
    }

    public int GetNext()
    {
        num++;
        if (_wanted == wanted.EvenNum)
        {
            if (num % 2 == 1)
            {
                num++;
            }
        }
        else if (_wanted == wanted.OddNum)
        {
            if (num % 2 == 0)
            {
                num++;
            }
        }
        return num;
    }
}