Valhalla Legends Forums Archive | .NET Platform | Oooh, I just wrote my first C# iterator property! :D

AuthorMessageTime
Myndfyr
I was trying to come up with an efficient way to iterate through the MPQ patch list backwards without loading them in reverse order in my code.  This is what I came up with:
[code]
public IEnumerable<MpqArchive> Patches
        {
            get
            {
                for (int i = m_patches.Length - 1; i >= 0; i--)
                {
                    yield return m_patches[i];
                }
            }
        }
[/code]

I've been having difficulty coming up with the utility for this.  I have to say I'm pretty impressed.  First I thought of a custom collection class, then I thought about overriding the GetEnumerator property of List<MpqArchive>, but that didn't pan out (nonvirtual method).  Then I thought about that, jotted it down, first compile I got it right and I was amazed at how straightfoward it was.

:D
July 13, 2006, 8:53 AM
Topaz
Can't you iterate backwards with lists?
July 13, 2006, 9:04 AM
Myndfyr
If you write a custom property for it.  List<T> for instance does not have any virtual methods, so I opted out of using that because I don't like to get the "Member xxx hides inherited member xxx" warning.  However, if you did something like:

[code]
public class SpecialList<T> : List<T>
{
    public IEnumerable<T> BackwardsList
    {
        get
        {
            for (int i = Count - 1; i >= 0; i--)
            {
                yield return this[i];
            }
        }
    }
}
[/code]

Then, to use the code, instead of foreach'ing the object, you foreach the property:
[code]
foreach (T item in mySpecialList.BackwardsList)
{
    // do something with the list backwards....
}
[/code]

It's just a more coherent way of doing things.  You could have done it in .NET 1.x too, but you needed to implement the IEnumerable interface.
July 13, 2006, 9:32 AM
Myndfyr
I'm looking at the decompilation of it in .NET Reflector:

[code]
public IEnumerable<MpqArchive> Patches
{
      get
      {
            InterfaceData.<get_Patches>d__0 d__1 = new InterfaceData.<get_Patches>d__0(-2);
            d__1.<>4__this = this;
            return d__1;
      }
}

[/code]
Then there's a hidden child subclass contained by InterfaceData (the class I added the Patches property to):
[code]
[CompilerGenerated]
private sealed class <get_Patches>d__0 : IEnumerable<MpqArchive>, IEnumerable, IEnumerator<MpqArchive>, IEnumerator, IDisposable
{
      // Methods
      [DebuggerHidden]
      public <get_Patches>d__0(int <>1__state);
      private bool MoveNext();
      [DebuggerHidden]
      IEnumerator<MpqArchive> IEnumerable<MpqArchive>.GetEnumerator();
      [DebuggerHidden]
      IEnumerator IEnumerable.GetEnumerator();
      [DebuggerHidden]
      void IEnumerator.Reset();
      void IDisposable.Dispose();

      // Properties
      MpqArchive IEnumerator<MpqArchive>.Current { [DebuggerHidden] get; }
      object IEnumerator.Current { [DebuggerHidden] get; }

      // Fields
      private int <>1__state;
      private MpqArchive <>2__current;
      public InterfaceData <>4__this;
      public int <i>5__1;
}
[/code]
So that's how it works.  The compiler generates a new class that implements all of the interfaces needed for foreach. :o
July 13, 2006, 9:37 AM
St0rm.iD
Welcome to Python :)
July 13, 2006, 6:25 PM

Search