lucenenet-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Simon Svensson <si...@devhost.se>
Subject Re: [Lucene.Net] [jira] [Created] (LUCENENET-469) Convert Java Iterator classes to implement IEnumerable<T>
Date Fri, 08 Jun 2012 20:32:45 GMT
Hi,

We could add IEnumerable<T> to TermEnum without affecting the current 
api. It would allow things like foreach(var t in reader.Terms()). 
Dispose _will_ be called by a foreach statement if the IEnumerator<T> 
implements IDisposable (not the IEnumerable<T>). However, the linq 
extension methods are at bit more quirky.  ToArray<T>(...) will create 
an internal Buffer<T> which will foreach (and dispose) as previously 
described. However, if the enumerable is also an ICollection<T>, then 
there will be no foreach, but a optimized call to ICollection<T>.CopyTo, 
and thus no call do IDisposable.Dispose. Where<T>(...) will (assuming 
we're not an T[] or List<T>) create an internal filtering iterator which 
will dispose our iterator.

The linq extension methods seems to dispose the iterator in all 
scenarios when one is created. I think we're in the clear as long as we 
don't implement ICollection<T> or derive from List<T>.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApplication {
     public static class Program {
         public static void Main() {
             Console.WriteLine("Normal foreach:");
             foreach (var t in Terms()) {
                 Console.WriteLine("  " + t);
             }

             Console.WriteLine("System.Linq:");
             var arr = Terms().ToArray();
             foreach (var t in arr) {
                 Console.WriteLine("  " + t);
             }

             Console.ReadLine();
         }

         // Somewhat simplified version of IndexReader.Terms()
         public static TermEnum Terms() {
             return new TermEnum();
         }

         public class TermEnum : IEnumerable<String> {
             private readonly String[] _texts = new[] { "term1", 
"term2", "term3" };
             private Int32 _position = -1;

             #region Existing api

             public Boolean Next() {
                 return (++_position < _texts.Length);
             }

             public String Text() {
                 return _texts[_position];
             }

             #endregion

             public IEnumerator<String> GetEnumerator() {
                 return new TermEnumEnumerator(this);
             }

             IEnumerator IEnumerable.GetEnumerator() {
                 return GetEnumerator();
             }
         }

         public class TermEnumEnumerator : IEnumerator<String> {
             private readonly TermEnum _owner;

             public TermEnumEnumerator(TermEnum owner) {
                 _owner = owner;
             }

             public void Dispose() {
                 Console.WriteLine("TermEnumEnumerator.Dispose()");
             }

             public Boolean MoveNext() {
                 return _owner.Next();
             }

             void IEnumerator.Reset() {
                 throw new NotImplementedException();
             }

             public String Current {
                 get { return _owner.Text(); }
             }

             Object IEnumerator.Current {
                 get { return Current; }
             }
         }
     }
}





On 2012-06-08 21:25, Andy Pook wrote:
> If we don't want to add IEnumerable (though it seems that IEnumerable could
> be added in parallel with the existing pattern) could we add a bunch of
> extension methods?
> Something like the following...
>
> {noformat}
> public static class LuceneExtensions
> {
> public static IEnumerable<Term>  GetEnumerable(this TermEnum termEnum)
> {
> yield return termEnum.Term();
> while (termEnum.Next())
> yield return termEnum.Term();
> }
> }
> {noformat}
>
> Then you can...
> {noformat}
> foreach(var e in myTernEnum.GetEnumerable())
> {
>      // do stuff with e
> }
> {noformat}
>
> Not as elegant as a direct implementation but gives easy enough access to
> foreach sematics.
>
>
> The second option is to realize that you don't need to explicitly implement
> IEnumerable. You just need a GetEnumerator method.
> So just add...
>
> {noformat}
> public IEnumerable<Term>  GetEnumerator()
> {
> yield return Term();
> while (Next())
> yield return Term();
> }
> {noformat}
>
> Now you get nice foreach sematics without even mentioning IEnumerable.
> Compiler magic is your friend :-)
>
> BTW: Dispose() is only called automatically when exiting a using block.
> Exiting a foreach will not.
>
> Cheers,
>    Andy
>
> On 24 January 2012 06:37, Christopher Currens (Created) (JIRA)<
> jira@apache.org>  wrote:
>
>> Convert Java Iterator classes to implement IEnumerable<T>
>> ---------------------------------------------------------
>>
>>                  Key: LUCENENET-469
>>                  URL: https://issues.apache.org/jira/browse/LUCENENET-469
>>              Project: Lucene.Net
>>           Issue Type: Sub-task
>>           Components: Lucene.Net Contrib, Lucene.Net Core
>>     Affects Versions: Lucene.Net 2.9.4, Lucene.Net 3.0.3, Lucene.Net 2.9.4g
>>          Environment: all
>>             Reporter: Christopher Currens
>>              Fix For: Lucene.Net 3.0.3
>>
>>
>> The Iterator pattern in Java is equivalent to IEnumerable in .NET.
>>   Classes that were directly ported in Java using the Iterator pattern,
>> cannot be used with Linq or foreach blocks in .NET.
>>
>> {{Next()}} would be equivalent to .NET's {{MoveNext()}}, and in the below
>> case, {{Term()}} would be as .NET's {{Current}} property.  In cases as
>> below, it will require {{TermEnum}} to become an abstract class with
>> {{Term}} and {{DocFreq}} properties, which would be returned from another
>> class or method that implemented {{IEnumerable<TermEnum>}}.
>>
>> {noformat}
>>         public abstract class TermEnum : IDisposable
>>         {
>>                 public abstract bool Next();
>>                 public abstract Term Term();
>>                 public abstract int DocFreq();
>>                 public abstract void  Close();
>>                 public abstract void Dispose();
>>         }
>> {noformat}
>>
>> would instead look something like:
>>
>> {noformat}
>>         public class TermFreq
>>         {
>>                 public abstract Term { get; }
>>                 public abstract int { get; }
>>         }
>>
>>         public abstract class TermEnum : IEnumerable<TermFreq>, IDisposable
>>         {
>>                 // ...
>>         }
>> {noformat}
>>
>> Keep in mind that it is important that if the class being converted
>> implements {{IDisposable}}, the class that is enumerating the terms (in
>> this case {{TermEnum}}) should inherit from both {{IEnumerable<T>}} *and*
>> {{IDisposable}}.  This won't be any change to the user, as the compiler
>> automatically calls {{IDisposable}} when used in a {{foreach}} loop.
>>
>> --
>> This message is automatically generated by JIRA.
>> If you think it was sent incorrectly, please contact your JIRA
>> administrators:
>> https://issues.apache.org/jira/secure/ContactAdministrators!default.jspa
>> For more information on JIRA, see: http://www.atlassian.com/software/jira
>>
>>
>>

Mime
View raw message