Tested with Microsoft Visual C# 2005 Beta 1, .Net 2.0.40607.42
C# 2.0 provides us with a way to implement IEnumerator for compatilibity with
foreach-in collection access: the yield keyword.
yield now delivers what GetEnumerator did with previous versions of
.Net, and it's much faster too!
However, I've found that building your own custom IEnumerator classes will
provide you with a faster result than with any of the other two standard
GetEnumerator/IEnumerator patterns.
In a test involving three different classes that implement three different ways to iterate through
a collection of one million strings, it's clear that using custom-built iterators are much faster.
Here are the results of my test:
.Net 1.0/1.1 Iterator Time: 296 milliseconds
.Net 2.0 Iterator Time: 93 milliseconds.
.Net Custom Iterator Time: 46 milliseconds.
Press any key to continue...
Console application that tests for TimeSpans between 3 enumerable collection classes/methods:
namespace Comparison1020Iterators
{
class Program
{
static void Main(string[] args)
{
My10CollectionClass mc10 = new My10CollectionClass();
DateTime dt10 = DateTime.Now;
foreach (String str in mc10)
{
// Do nothing...continue...
}
TimeSpan ts10 = DateTime.Now.Subtract(dt10);
My20CollectionClass mc20 = new My20CollectionClass();
DateTime dt20 = DateTime.Now;
foreach (String str in mc20)
{
// Do nothing...continue...
}
TimeSpan ts20 = DateTime.Now.Subtract(dt20);
MyCustomCollectionClass mcCustom = new MyCustomCollectionClass();
DateTime dtCustom = DateTime.Now;
foreach (String str in mcCustom)
{
// Do nothing...continue...
}
TimeSpan tsCustom = DateTime.Now.Subtract(dtCustom);
Console.WriteLine(".Net 1.0/1.1 Iterator Time: {0} milliseconds.",
ts10.Milliseconds.ToString());
Console.WriteLine(".Net 2.0 Iterator Time: {0} milliseconds.",
ts20.Milliseconds.ToString());
Console.WriteLine(".Net Custom Iterator Time: {0} milliseconds.",
tsCustom.Milliseconds.ToString());
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
}
public class My20CollectionClass
{
private String[] m_Strings;
public My20CollectionClass()
{
this.m_Strings = new String[1000000];;
}
public System.Collections.IEnumerator GetEnumerator()
{
foreach (String str in this.m_Strings)
yield return str;
}
}
public class My10CollectionClass
{
private String[] m_Strings;
public My10CollectionClass()
{
this.m_Strings = new String[1000000];;
}
public System.Collections.IEnumerator GetEnumerator()
{
return this.m_Strings.GetEnumerator();
}
}
public class MyCustomCollectionClass :
System.Collections.IEnumerator
{
private String[] m_Strings;
private int m_CurrentIndex = -1;
public MyCustomCollectionClass()
{
this.m_Strings = new String[1000000];;
}
public bool MoveNext()
{
bool bln = true;
this.m_CurrentIndex++;
if (this.m_CurrentIndex > this.m_Strings.Length - 1)
bln = false;
return bln;
}
public void Reset()
{
this.m_CurrentIndex = -1;
}
public Object Current
{
get
{
if (this.m_CurrentIndex == -1)
this.MoveNext();
return this.m_Strings[this.m_CurrentIndex];
}
}
public System.Collections.IEnumerator GetEnumerator()
{
return this;
}
}
}
If you look at the numbers, you'll see that custom built iterators are faster than .Net 2.0 iterators. That was really my point, not that 2.0 iterators are faster than 1.0 iterators.By peter @ 11/2/2005 3:40:08 AM
>this.m_Strings = new String[1000000];
so wasteful!By Mike G. @ 12/8/2005 6:26:02 PM
RE: this.m_Strings = new String[1000000];
It's a test - not something you'd want to write for a production application.By Chris Mullins @ 8/18/2006 2:04:25 PM
Your C# .Net 2.0 Iterator is still going through a bit more work than it needs to. The enumerator you're using is object base, which means it's being cast to a string when it's used.
Replace:
public IEnumerator GetEnumerator()
With the Generic Version:
public IEnumerator>string< GetEnumerator()
This will help a bit with strong typing, and may show a modest gain.By geaalvdm @ 10/20/2007 4:41:40 AM