¿Cómo puedo implementar IEnumerable


Sé cómo implementar elerableumerable no genérico, así:

using System;
using System.Collections;

namespace ConsoleApplication33
{
    class Program
    {
        static void Main(string[] args)
        {
            MyObjects myObjects = new MyObjects();
            myObjects[0] = new MyObject() { Foo = "Hello", Bar = 1 };
            myObjects[1] = new MyObject() { Foo = "World", Bar = 2 };

            foreach (MyObject x in myObjects)
            {
                Console.WriteLine(x.Foo);
                Console.WriteLine(x.Bar);
            }

            Console.ReadLine();
        }
    }

    class MyObject
    {
        public string Foo { get; set; }
        public int Bar { get; set; }
    }

    class MyObjects : IEnumerable
    {
        ArrayList mylist = new ArrayList();

        public MyObject this[int index]
        {
            get { return (MyObject)mylist[index]; }
            set { mylist.Insert(index, value); }
        }

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

Sin embargo, también noto que Iumerable tiene una versión genérica, IEnumerable<T>, pero no puedo averiguar cómo implementarla.

Si añado using System.Collections.Generic; a mis directivas de uso, y luego cambio:

class MyObjects : IEnumerable

A:

class MyObjects : IEnumerable<MyObject>

Y luego haga clic derecho en IEnumerable<MyObject> y seleccione Implement Interface => Implement Interface, Visual Studio agrega el siguiente bloque de código:

IEnumerator<MyObject> IEnumerable<MyObject>.GetEnumerator()
{
    throw new NotImplementedException();
}

Devolviendo el objeto genericumerable no genérico desde el GetEnumerator(); el método no funciona esta vez, así que ¿qué pongo aquí? La CLI ahora ignora la implementación no genérica y se dirige directamente a la versión genérica cuando intenta enumerar a través de mi matriz durante el bucle foreach.

Author: johnnyRose, 2012-07-02

6 answers

Si elige usar una colección genérica, como List<MyObject> en lugar de ArrayList, encontrará que List<MyObject> proporcionará enumeradores genéricos y no genéricos que puede usar.

using System.Collections;

class MyObjects : IEnumerable<MyObject>
{
    List<MyObject> mylist = new List<MyObject>();

    public MyObject this[int index]  
    {  
        get { return mylist[index]; }  
        set { mylist.Insert(index, value); }  
    } 

    public IEnumerator<MyObject> GetEnumerator()
    {
        return mylist.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}
 125
Author: Monroe Thomas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-11 18:56:00

Probablemente no quieras una implementación explícita de IEnumerable<T> (que es lo que has mostrado).

El patrón habitual es usar el GetEnumerator de IEnumerable<T> en la implementación explícita deerableumerable:

class FooCollection : IEnumerable<Foo>, IEnumerable
{
    SomeCollection<Foo> foos;

    // Explicit for IEnumerable because weakly typed collections are Bad
    System.Collections.IEnumerator IEnumerable.GetEnumerator()
    {
        // uses the strongly typed IEnumerable<T> implementation
        return this.GetEnumerator();
    }

    // Normal implementation for IEnumerable<T>
    IEnumerator<Foo> GetEnumerator()
    {
        foreach (Foo foo in this.foos)
        {
            yield return foo;
            //nb: if SomeCollection is not strongly-typed use a cast:
            // yield return (Foo)foo;
            // Or better yet, switch to an internal collection which is
            // strongly-typed. Such as List<T> or T[], your choice.
        }

        // or, as pointed out: return this.foos.GetEnumerator();
    }
}
 45
Author: user7116,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-02 15:58:32

¿por Qué lo haces manualmente? yield return automatiza todo el proceso de manejo de iteradores. (También escribí sobre ello en mi blog, incluyendo un vistazo al código generado por el compilador).

Si realmente quieres hacerlo tú mismo, también tienes que devolver un enumerador genérico. Ya no podrás usar un ArrayList ya que no es genérico. Cámbialo a List<MyObject> en su lugar. Eso, por supuesto, supone que solo tiene objetos de tipo MyObject (o tipos derivados) en su colección.

 22
Author: Anders Abel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-02 15:50:57

Si trabaja con genéricos, use List en lugar de ArrayList. La Lista tiene exactamente el método GetEnumerator que necesita.

List<MyObject> myList = new List<MyObject>();
 4
Author: Amiram Korach,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-02 15:42:15

Hacer mylist en un List<MyObject>, es una opción

 0
Author: ColWhi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-02 15:40:12

Tenga en cuenta que el IEnumerable<T> ya está implementado por el System.Collections por lo que otro enfoque es derivar su clase MyObjects de System.Collections como una clase base (documentación):

Sistema.Colecciones: Proporciona la clase base para una colección genérica.

Más tarde podemos hacer nuestra propia implementación para anular los métodos virtuales System.Collections para proporcionar un comportamiento personalizado (solo para ClearItems, InsertItem, RemoveItem, y SetItem junto con Equals, GetHashCode, y ToString de Object). A diferencia de la List<T> que no está diseñado para ser fácilmente extensible.

Ejemplo:

public class FooCollection : System.Collections<Foo>
{
    //...
    protected override void InsertItem(int index, Foo newItem)
    {
        base.InsertItem(index, newItem);     
        Console.Write("An item was successfully inserted to MyCollection!");
    }
}

public static void Main()
{
    FooCollection fooCollection = new FooCollection();
    fooCollection.Add(new Foo()); //OUTPUT: An item was successfully inserted to FooCollection!
}

Tenga en cuenta que conducir desde collection solo se recomienda en caso de que se necesite un comportamiento de recopilación personalizado, lo que rara vez ocurre. ver uso .

 -1
Author: Shahar Shukrani,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-10-02 21:07:36