2008-09-24 5 views
8

Assumer la classe suivante:Comment déléguer l'implémentation de l'interface à l'autre classe en C#

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

Il est nécessaire de mettre en œuvre les méthodes IEnumerator dans MyEnum. Mais est-il possible de 'déléguer' ou de rediriger directement l'implémentation pour IEnumerator vers _myList sans avoir besoin d'implémenter les méthodes IEnumerator?

Répondre

7

Méthode 1: Continuer à utiliser l'encapsulation et transférer les appels à l'implémentation de la liste.

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éthode 2: Hériter de la mise en œuvre de la liste que vous obtenez ce comportement gratuitement.

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éthode 1 permet de mieux sandboxing car il n'y a pas de méthode qui sera appelée liste sans connaissance MyEnum. Pour le moindre effort La méthode 2 est préférée.

-1

À moins que vous ne dériviez de la liste < T>.

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

Ok, cela fonctionne, mais je veux être sûr que le code d'appel est incapable de type coulée l'énumérateur à List à nouveau et ajouter ou supprimer des objets de celui-ci. – Willem

1

Vous pouvez le faire:

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

La raison est simple. Votre classe peut contenir plusieurs champs qui sont des collections, donc compilateur/environnement ne peut pas savoir quel champ doit être utilisé pour implémenter "IEnumerator".

EIDT: Je suis d'accord avec @pb - vous devez implémente IEnumerator < SomeObject Interface >.

+0

L'interface à implémenter est IEnumerable et non IEnumerator. –

0

Si vous voulez retourner une collection d'une manière où l'appelant est incapable de modifier la collection, vous pouvez envelopper la liste dans un ReadOnlyCollection <> et retour IEnumerable <> du ReadOnlyCollection <>. De cette façon, vous pouvez être sûr que votre collection ne sera pas modifiée.

1

En dehors de l'utilisation de la méthode pb, cela n'est pas possible pour une raison "simple": la méthode d'interface doit passer un pointeur this comme premier argument. Lorsque vous appelez GetEnumerator sur votre objet, ce pointeur sera votre objet. Cependant, pour que l'invocation fonctionne sur la liste imbriquée, le pointeur doit être une référence à cette liste, pas votre classe.

Par conséquent, vous devez explicitement déléguer la méthode à l'autre objet.

(Et en passant, les conseils de l'autre réponse avait raison: utiliser IEnumerator<T>, pasIEnumerable!)

-1

Merci à tous pour vos commentaires et explications. Finalement, j'ai combiné certaines de vos réponses aux questions suivantes:

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(); 
    } 
} 

Cette solution est d'assurer le code appelant est incapable de modifier la liste et chaque recenseur est indépendant des autres dans tous les sens (par exemple avec le tri) . Merci encore.

+0

Vous pouvez passer par 'ReadOnlyCollection' car' IEnumerable's sont immutables quand même! L'utilisateur doit upcast et deviner le type d'origine de la liste afin de le modifier. Copier la liste est à mon humble avis pas une très bonne idée. –

-1

Notez que grâce à duck-typing, vous pouvez utiliser foreach sur un objet qui a une méthode GetEnumerator - le type d'objet n'a pas besoin de mettre en œuvre effectivement IEnumerable.

Donc, si vous faites ceci:

class SomeObject 
{ 
} 

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

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

Alors ceci fonctionne très bien:

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

Je réalise qu'il ne s'agit pas d'une réponse générale à la question initiale, mais qu'elle est pertinente pour le cas d'utilisation spécifique fourni dans la question. – yoyo

+0

Si vous réalisez que vous ne répondez pas à la question, alors * ne postez pas de réponse à la question *. Les réponses sont pour répondre à la question, pas pour poster des faits triviaux aléatoires que vous trouvez intéressants. Cela ne vous aide pas vraiment dans cette situation; il n'y a aucune raison pour que vous n'implémentiez pas réellement l'interface dans cette situation. – Servy

+0

La question était de savoir comment déléguer l'implémentation d'une interface afin d'éviter d'écrire du code standard. Ma réponse est une réponse potentielle pour le cas courant de déléguer l'implémentation de IEnumerable, qui est aussi l'exemple utilisé par le PO. J'ai débattu de l'opportunité d'en faire un commentaire ou une réponse, et j'ai décidé d'en faire une réponse. C'est * une * réponse à une forme spécifique de la question. – yoyo

Questions connexes