My fun with IKVM.NET continues this week as I utilize Weka from .NET (just a fun note, but the .NET-compiled version is insanely faster than the Java version doing the exact same thing; suck on that, Java fans!).  For the most part, everything has been swell.  The hardest part is trying to decipher research methodologies to replicate the systems they describe.  Still, I’ve run into a few snags when working with the .NET versions of Weka, the first of which is that you can’t foreach over a Java Enumeration.  For example, consider the following:

   1: //THE FOLLOWING DOESN'T COMPILE!
   2: //foreach (weka.core.Instance instance in instances.enumerateInstances())
   3: //{
   4: //    //TODO: Operate on instance here.
   5: //}
   6:  
   7: Enumeration enumerator = instances.enumerateInstances();
   8: while (enumerator.hasMoreElements())
   9: {
  10:     weka.core.Instance instance = (weka.core.Instance)enumerator.nextElement();
  11:  
  12:     //TODO: Operate on instance here
  13: }

While it isn’t a huge difference, being able to use foreach would obviously be simpler than having to create an instance of Enumeration, then use it to step through the items.  Fortunately, it’s quite easy to generically bridge the gap so that any Enumeration can be enumerated by simply calling an extension method, like so:

   1: foreach (weka.core.Instance instance in instances.enumerateInstances().ToEnumerable())
   2: {
   3:     //TODO: Operate on instance
   4: }

How does this work?  First, we need to apply the adapter pattern to convert a Java Enumeration into a .NET IEnumerator.  Here’s our adapter:

   1: /// <summary>
   2: /// Provides an adapter that can convert a Java
   3: /// Enumeration class into something that implements
   4: /// IEnumerator.  
   5: /// </summary>
   6: public class EnumeratorEnumerationAdapter : IEnumerator
   7: {
   8:     #region Private Fields
   9:  
  10:     /// <summary>
  11:     /// The class being adapted.
  12:     /// </summary>
  13:     private Enumeration mEnumeration;
  14:  
  15:     /// <summary>
  16:     /// The current object.
  17:     /// </summary>
  18:     private object mCurrent;
  19:  
  20:     #endregion
  21:  
  22:     #region Implementation of IEnumerator
  23:  
  24:     /// <summary>
  25:     /// Advances the enumerator to the next element of the collection.
  26:     /// </summary>
  27:     /// <returns>
  28:     /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection.
  29:     /// </returns>
  30:     /// <exception cref="T:System.InvalidOperationException">The collection was modified after the enumerator was created. </exception><filterpriority>2</filterpriority>
  31:     public bool MoveNext()
  32:     {
  33:         if (!mEnumeration.hasMoreElements())
  34:         {
  35:             return false;
  36:         }
  37:  
  38:         mCurrent = mEnumeration.nextElement();
  39:         return true;
  40:     }
  41:  
  42:     /// <summary>
  43:     /// Sets the enumerator to its initial position, which is before the first element in the collection.
  44:     /// </summary>
  45:     /// <exception cref="T:System.InvalidOperationException">The collection was modified after the enumerator was created. </exception><filterpriority>2</filterpriority>
  46:     public void Reset()
  47:     {
  48:         throw new NotSupportedException();
  49:     }
  50:  
  51:     /// <summary>
  52:     /// Gets the current element in the collection.
  53:     /// </summary>
  54:     /// <returns>
  55:     /// The current element in the collection.
  56:     /// </returns>
  57:     /// <exception cref="T:System.InvalidOperationException">The enumerator is positioned before the first element of the collection or after the last element.-or- The collection was modified after the enumerator was created.</exception><filterpriority>2</filterpriority>
  58:     public object Current
  59:     {
  60:         get
  61:         {
  62:             return mCurrent;
  63:         }
  64:     }
  65:  
  66:     #endregion
  67:  
  68:     #region Public Constructors
  69:  
  70:     /// <summary>
  71:     /// Creates an adapter for the specified enumeration.
  72:     /// </summary>
  73:     /// <param name="enumeration"></param>
  74:     public EnumeratorEnumerationAdapter(Enumeration enumeration)
  75:     {
  76:         mEnumeration = enumeration;
  77:         mCurrent = null;
  78:     }
  79:  
  80:     #endregion
  81: }

Next, we just need to write the extension method that utilizes our adapter to create an IEnumerable:

   1: /// <summary>
   2: /// Contains extension methods to simplify working with 
   3: /// <see cref="Enumeration"/> objects.
   4: /// </summary>
   5: public static class EnumerationExtensions
   6: {
   7:     /// <summary>
   8:     /// Creates a <see cref="IEnumerable"/> wrapper
   9:     /// around a <see cref="Enumeration"/>.
  10:     /// </summary>
  11:     /// <param name="enumeration"></param>
  12:     /// <returns></returns>
  13:     public static IEnumerable ToEnumerable(this Enumeration enumeration)
  14:     {
  15:         EnumeratorEnumerationAdapter adapter = new EnumeratorEnumerationAdapter(enumeration);
  16:  
  17:         while (adapter.MoveNext())
  18:         {
  19:             yield return adapter.Current;
  20:         }
  21:     }
  22: }

And like magic, you can now foreach over any Java Enumeration just like it was a .NET IEnumerable implementor.  It’d be nice if this were baked in to IKVM.NET, but for now, this simple "hack" will do the trick.