Número 50julio-AGOSTO 2008

Visual Basic•C#•ASP.NET•ADO.NET•AJAXSilverlight.NET Framework

dotNetManía

Revista dedicada a los profesionales de la plataforma .NET

Menú

Inicio

Números publicados

Libros

Próximo número (nº51)

Autores

¿Qué es dotNetManía?

Garantía de satisfacción

Contactar

Pedidos

Suscripciones

Renovaciones

Libros

Noticias dnm

Alhambra-Eidos llega a un acuerdo con dotNetManía para la difusión conjunta de su oferta formativa. Leer más...


Disponibles los primeros 28 números de dotNetManía en formato PDF y de libre distribución. Leer más... 

Patrocinadores

Patrocinador Oro
Microsoft

Patrocinadores Plata
Alhambra-Eidos
Solid Quality Mentors

Patrocinadores Bronce
Raona
Plain Concepts
Krasis
ABOX 

 

 

 

Nº 7 Septiembre 2004 Enumeradores e Iteradores en C# y C# 2.0 Material de apoyo

Por Miguel Katrib y Mario del Valle
 

En este trabajo se ilustra la utilidad de los enumeradores y del ciclo foreach en C#. Se analizan cuáles son las limitaciones de estos enumeradores que justifican la importancia de la nueva inclusión de iteradores en el venidero C# 2.0. Se ejemplifican las ventajas de estos iteradores en C# 2.0 para escribir
código más elegante, legible y menos propenso a errores. Finalmente se proporciona una implementación de iteradores por medio de hebras que, además de ilustrar la utilización de las hebras, ofrece una forma concreta de usar iteradores en el actual C#.


Código fuente

class EvenEnumerator: IEnumerator

{

 bool moveOK;

 int currentValue, lower, upper;

 public EvenEnumerator(int lowerBound, int upperBound)

 {

  if (lowerBound  > upperBound)

     throw new ArgumentException("Wrong interval");

  if (lowerBound % 2 != 0) lower = lowerBound-1;

  else lower = lowerBound – 2;

  upper = upperBound;

  Reset();

 }

 public bool MoveNext()

 {

  if (currentValue > upper)

     return false;

  currentValue = currentValue+2;

  moveOK = currentValue<=upper;

  return moveOK;

 }

 public object Current

 {

  get

  {

   if (moveOK)

     return currentValue;

   else

     throw new InvalidOperationException("There is no current element");

  }

 }

 public void Reset()

 {

  moveOK = false;

  currentValue = lower;

 }

}

 

Código fuente

class Tree

{

 object nodeValue;

 public ArrayList Nodes

 {

  get{…}

 }

 public IEnumerable NodesInPreOrder

 {

  get { return new PreOrderEnumerable(this);}

 }

 //Inner class

 class PreOrderEnumerable:IEnumerable

 {

  Tree t;

  public PreOrderEnumerable(Tree t){this.t=t;}

  public IEnumerator GetEnumerator()

  {

   return new PreOrderEnumerator(t);

  }

  class PreOrderEnumerator: IEnumerator

  {

   Tree t;

   Stack s;

   object current;

   bool moveOK;

   public PreOrderEnumerator(Tree t)

   {

    if (t==null)

     throw new InvalidArgumentException("Null parameter");

    this.t=t; s = new Stack(); Reset();

   }

   public bool MoveNext()

   {

    if (s.Empty) return false;

    else

    {

     Tree t = s.Pop();

     current = t.nodeValue;

     moveOK = true;

     if (t.Nodes!=null)

      for (int k = t.Nodes.Count-1; k>=0, k--)

        s.Push(t.Nodes[k]);

     return moveOK;

    }

   }

   public object Current

   {

    if (moveOK) return current;

    else

     throw new InvalidOperationException("Enumeration is out of limit");

   }

   public void Reset()

   {

    s.Clear(); s.Push(t);

   }

  }

 }

}

 

Código fuente

class Tree

{

      object nodeValue;

      ...

      public ArrayList Nodes

      {

            get{...}

      }

      public IEnumerable PreOrder

      {

            get

            {

              return new Iterator(new IteratorMethod(PreOrderMethod));

            }

      }

      void PreOrderMethod(IYield y)

      {

            PreOrderMethod(y, this);

      }

      void PreOrderMethod(IYield y, Tree t)

      {

            y.Yield(t.nodeValue);

            foreach (Tree t1 in t.Nodes) PreOrderMethod(y, t1);

      }

}

class TreeTest

{

  public static void Main()

  {

   Tree t = ...;

   foreach (object x in t.PreOrder)

      Console.WriteLine(x);

  }

}

 

Fuente 1.

Código fuente

public class Iterator: IEnumerable

{    

  IteratorMethod it;

  public Iterator(IteratorMethod it)

  {

    if (it == null)

      throw new ArgumentNullException();

    this.it = it;

  }

  public IEnumerator GetEnumerator()

  {

    return new CoroutineEnumerator(it);

  } 

 

  //Inner class

  class CoroutineEnumerator : IEnumerator, IDisposable, IYield

  {

    IteratorMethod it;

    Thread itThread;

    object current;

    bool finish;

    object proceedIteration = new object();

    object calculatedValue = new object();

 

    public CoroutineEnumerator(IteratorMethod iterator)

    {

     this.iterator = iterator;

    }

 

    void runMethod()        {

      finish = false;

      //Initialize a thread with the handler

      it(this);

      finish = true;

      lock(calculatedValue){Monitor.Pulse(calculatedValue);}

    }

 

      public bool MoveNext()

    {

     lock(calculatedValue)

     {

       if (itThread == null)

       {

        itThread = new Thread(new ThreadStart(runMethod));

        itThread.Start();

       }

       lock (proceedIteration)

       {

        Monitor.Pulse(proceedIteration);

       }

       Monitor.Wait(calculatedValue);

     }

     return !finish;

    }

 

    public object Current

    {

     get

     {

       if (finish)  throw new InvalidOperationException(

                           "Invalid Current. Out of the collection");

       else return current;

     }

    }

 

    void IYield.Yield(object result)

    {

     lock (proceedIteration)

     {

      lock (calculatedValue)

      {

       current = result;

       Monitor.Pulse(calculatedValue);

      }

      Monitor.Wait(proceedIteration);

     }

    }

 

      public void Reset()

    {

     try

     {

      if (itThread.IsAlive)

        itThread.Abort();

     }

     catch(ThreadAbortException){};

     itThread = null;

     finish = true;

    }

 

   ~CoroutineEnumerator()

   {

    Dispose();

   }

 

   public void Dispose()

   {

    if (itThread != null)

    {

     try

     {

      itThread.Abort();

     }

     catch(ThreadAbortException){};

    itThread = null;

   }

  }

 }

}

 

Fuente 2.

Código fuente

class Hanoi

{

      int disks;

      string target, source, aux;

      public Hanoi(int disks, string source, string target, string aux)

      {

            this.disks=disks; this.source=source;

            this.target=target; this.aux=aux;

      }

      public IEnumerable Movements

      {

            get {return new Iterator(new IteratorMethod(HanoiMethod));}

      }

      void HanoiMethod(IYield y)

      {

            HanoiMethod(y, disks, source, target, aux);

      }

      void HanoiMethod(IYield y, int disks, string source,

           string target, string aux)

      {

       if (disks==1) y.Yield("Move from " + source + " to " + target);

       else

            {

                  HanoiMethod(y, disks-1,source, aux, target);

                  y.Yield("Move from " + source + " to " + target);

                  HanoiMethod(y, disks-1,aux, target, source);

            }

      }

}

 

 


Volver
 

 

dotNetManía es una revista editada por Netalia. Más información.