我希望有一个枚举器/生成器,每当我调用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
...
我不会在一个地方进行迭代,而是在许多地方和非常不同的时间进行迭代。
我如何以最优雅的方式做到这一点?如果它也快,那也很好。
答案 0 :(得分:5)
术语“枚举器”在这里有点误导,因为这是一种具有开头和结尾的特定类型的序列。在你的情况下,你不是枚举每个说法,而只是无限期地推进到下一个值。听起来非常适合单身:
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的误用,仅仅是因为这种情况和这种情况在某些方面看似相似,但却不一样。使用一个非常具体,有目的的界面,因为它所做的多件事情中的一件与你需要的东西相似(不相同)会回来咬你。
答案 1 :(得分:3)
var stringEnumerator = Enumerable.Range(1, 99).Select(i => string.Format("Identifier{0:00}.xml", i));
var numberEnumerator = Enumerable.Range(0, int.MaxValue/2).Select(i => 2*i);
答案 2 :(得分:2)
它是.net
的一部分IEnumerable<T>.GetEnumerator()
http://msdn.microsoft.com/en-us/library/s793z9y2.aspx和http://msdn.microsoft.com/en-us/library/78dfe2yb.aspx
编辑:
所以有了Linq魔法,你的代码可能是:
var myStringEnumerator= Enumerable
.Range(1,99)
.Select(n=>"Identifier"+n.ToString("00")+".xml")
.GetEnumerator();
if(myStringEnumerator.MoveNext())
//myStringEnumerator.Current;
我相信你可以为自己完成剩下的工作。
如果你真的需要一个“无限”的枚举,使用yield语句也可能是一个不错的选择,但你的字符串格式化让我觉得99是最大的
答案 3 :(得分:2)
public IEnumerable<string> GetFileNames()
{
for (int i = 1; i <= 99; i++)
{
yield return string.Format("Identifier{0:00}.xml", i);
}
}
使用它:
string filename;
foreach (string tmp in GetFileNames())
{
if (!File.Exists(tmp))
{
filename = file;
break;
}
}
要在没有foreach的情况下使用它,那么你可以这样做:
IEnumerator<string> names = GetFileNames().GetEnumerator();
names.MoveNext();
string name1 = names.Current;
names.MoveNext();
string name2 = names.Current;
// etc, etc.
满足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();
}
答案 4 :(得分:1)
听起来你真的想要一个静态函数,如下所示:
static class FileNames {
static int nextNumber;
public static string NextName() {
nextNumber++;
return String.Format(CultureInfo.InvariantCulture, "Indentifier{0:00}.xml", nextNumber);
}
}
请注意,这将从一个开始,而不是零。要使其从零开始,请将nextNumber
初始化为-1。 编辑:或者,删除第一行(nextNumber++
)并将第二行中的参数更改为++nextNumber
。
另外,这不是线程安全的。如果要在多个线程上调用它,请使用Interlocked.Increment
。
答案 5 :(得分:1)
这样的简单事情怎么样?
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;
}
}
答案 6 :(得分:0)
最简单的方法是使用iterators。例如:
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";
}
除了返回类型之外,您还可以返回IEnumerable
而不是IEnumerator
而不返回任何内容。 IEnumerable是一个对象,它创建枚举它的IEnumerator,并且可以在foreach
循环中使用。请注意,如果您返回IEnumerable,则每次枚举它时,您的代码都会再次运行(由不同的枚举器)。
要在不同的方法中使用它,您可以在静态字段中共享它们之间的IEnumerator。
答案 7 :(得分:0)
枚举器很好,因为你可以在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);
}
将产生:
Identifier01.xml
Identifier02.xml
Identifier03.xml
Identifier04.xml
Identifier05.xml