2008-09-24 18 views
8

Supongamos la siguiente clase:Cómo delegar implementación de la interfaz a otra clase en C#

public class MyEnum: IEnumerator 
{ 
    private List<SomeObject> _myList = new List<SomeObject>(); 
... 
} 

Es necesario poner en práctica los métodos IEnumerator en MyEnum. ¿Pero es posible 'delegar' o redirigir la implementación de IEnumerator directamente a _myList sin la necesidad de implementar los métodos de IEnumerator?

Respuesta

7

Método 1: Continuar utilizando encapsulación y reenviar llamadas a la implementación de la lista.

class SomeObject 
{ 
} 

class MyEnum : IEnumerable<SomeObject> 
{ 
    private List<SomeObject> _myList = new List<SomeObject>(); 

    public void Add(SomeObject o) 
    { 
     _myList.Add(o); 
    } 

    public IEnumerator<SomeObject> GetEnumerator() 
    { 
     return _myList.GetEnumerator(); 
    } 

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

class Program 
{ 
    static void Main(string[] args) 
    { 
     MyEnum a = new MyEnum(); 
     a.Add(new SomeObject()); 

     foreach (SomeObject o in a) 
     { 
      Console.WriteLine(o.GetType().ToString()); 
     } 

     Console.ReadLine(); 
    } 
} 

Método 2: Heredar de implementación de la lista se obtiene que el comportamiento de forma gratuita.

class SomeObject 
{ 
} 

class MyEnum : List<SomeObject> 
{ 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     MyEnum a = new MyEnum(); 
     a.Add(new SomeObject()); 

     foreach (SomeObject o in a) 
     { 
      Console.WriteLine(o.GetType().ToString()); 
     } 

     Console.ReadLine(); 
    } 
} 

Método 1 permite una mejor caja de arena ya que no hay método que se llama en la lista sin el conocimiento MyEnum. Por el menos esfuerzo Se prefiere el método 2.

-1

No, a menos que provenga de la lista < T>.

public class MyEnum : List<SomeObject>, IEnumerable<SomeObject>{} 
+0

Ok, esto va a funcionar, pero quiero estar seguro de que el código de llamada es incapaz de encasillamiento el enumerador a Enumerar nuevamente y agregar o eliminar objetos de él. – Willem

1

Usted puede hacer esto:

public class MyEnum : IEnumerator { 
    private List<SomeObject> _myList = new List<SomeObject>(); 
    public IEnumerator GetEnumerator() { return this._myList.GetEnumerator(); } 
} 

La razón es simple. Su clase puede contener varios campos que son colecciones, por lo que el compilador/entorno no puede saber qué campo se debe usar para implementar "IEnumerator".

eidt: Estoy de acuerdo con @pb - usted debe implementa IEnumerator <SomeObject> interfaz.

+0

La interfaz para implementar es IEnumerable not IEnumerator. –

0

Si desea devolver una colección de una manera en que la persona que llama no es capaz de modificar la colección, es posible que desee para envolver la lista en un ReadOnlyCollection <> y volver IEnumerable <> de la ReadOnlyCollection <>.

De esta forma puede estar seguro de que su colección no cambiará.

1

Además de usar el método de pb, esto no es posible por una razón "simple": el método de interfaz necesita pasar un puntero this como primer argumento. Cuando llame al GetEnumerator en su objeto, este puntero será su objeto. Sin embargo, para que la invocación funcione en la lista anidada, el puntero debería ser una referencia a esa lista, no a su clase.

Por lo tanto, debe delegar explícitamente el método en el otro objeto.

(Y por cierto, el asesoramiento en la otra respuesta era correcta: el uso IEnumerator<T>, no IEnumerable!)

-1

Gracias a todos por sus comentarios y explicaciones. el tiempo me han combinado algunas de sus respuestas a las siguientes:

class MyEnum : IEnumerable<SomeObject> 
{ 
    private List<SomeObject> _myList = new List<SomeObject>(); 
    public IEnumerator<SomeObject> GetEnumerator() 
    { 
     // Create a read-only copy of the list. 
     ReadOnlyCollection<CustomDevice> items = new ReadOnlyCollection<CustomDevice>(_myList); 
     return items.GetEnumerator(); 
    } 
} 

Esta solución es asegurar el código de llamada es incapaz de modificar la lista y cada empadronador es independiente de las demás en todos los sentidos (por ejemplo, con la clasificación) . Gracias de nuevo.

+0

Puede pasar por 'ReadOnlyCollection' porque' IEnumerable's es inmutable de todos modos! El usuario debería subir y adivinar el tipo original de la lista para modificarlo. Copiar la lista es en mi humilde opinión no es una muy buena idea. –

-1

Tenga en cuenta que gracias a duck-typing, puede utilizar foreach en cualquier objeto que tiene un método GetEnumerator - el tipo de objeto no necesita realmente implementar IEnumerable.

Así que si usted hace esto:

class SomeObject 
{ 
} 

class MyEnum 
{ 
    private List<SomeObject> _myList = new List<SomeObject>(); 

    public IEnumerator<SomeObject> GetEnumerator() 
    { 
     return _myList.GetEnumerator(); 
    } 
} 

entonces funciona muy bien:

MyEnum objects = new MyEnum(); 
// ... add some objects 
foreach (SomeObject obj in objects) 
{ 
    Console.WriteLine(obj.ToString()); 
} 
+0

Me doy cuenta de que esta no es una respuesta general a la pregunta original, pero es relevante para el caso de uso específico proporcionado en la pregunta. – yoyo

+0

Si se da cuenta de que no está respondiendo la pregunta, * no publique una respuesta a la pregunta *. Las respuestas son para responder la pregunta, no para publicar hechos triviales al azar que le parezcan interesantes. Esto no te está ayudando en esta situación; no hay ninguna razón para que no implemente la interfaz en esta situación. – Servy

+0

La pregunta era cómo delegar la implementación de una interfaz para evitar escribir código repetitivo. Mi respuesta es una respuesta potencial para el caso común de delegar la implementación de IEnumerable, que también es el ejemplo utilizado por el OP. Debatí si hacer un comentario o una respuesta, y decidí convertirlo en una respuesta. * Es * una respuesta a una forma específica de la pregunta. – yoyo

Cuestiones relacionadas