2010-07-06 3 views
3

J'ai remarqué que IEnumerable (Generics) nécessite 2 méthodes à mettre en œuvre:Question A propos IEnumerable <T>

1. IEnumerator<T> GetEnumerator()

2. IEnumerable.GetEnumerator() Méthode

(http://msdn.microsoft.com/en-us/library/19e6zeyy.aspx)

Qu'est-ce que # 2 et ho w je suis censé définir/mettre en œuvre cela? De mon jeu avec du code, il semble que IEnumerator GetEnumerator() est appelé dans la boucle foreach. Où le numéro 2 IEnumerable.GetEnumerator entre-t-il en jeu? Je suivais la recette 6.1 Créer un Iterator sur un type générique dans le livre de recettes C# 3.0 d'Oreilly et j'obtenais une erreur parce que # 2 n'était pas implémenté (il n'était pas inclus dans le code de recette).

Merci!

+0

double possible de [. Message d'erreur concernant IEnumerable.GetEnumerator()] (http://stackoverflow.com/questions/2981615/error-message- concernant-ienumerable-getenumerator) –

+0

Wow. Vous êtes géniaux les gars! Merci pour l'aide. Oui, ce que j'ai fait était de retourner GetEnumerator() dans la méthode non générique. – Abe

Répondre

9

Le premier est le GetEnumerator générique, tandis que le second est le générique. Ils font fonctionnellement le même travail, mais le non-générique ne peut renvoyer qu'un type object.

La meilleure façon de mettre en œuvre ces moyens consiste à mettre en œuvre la version générique, puis fournir ce pour la non-générique:

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

# 2 est le explicite implémentation non générique de la méthode GetEnumerator de l'interface IEnumerable. # 1 dans votre exemple est l'implémentation de GetEnumerator() pour l'interface IEnumerable<T>.

IEnumerable.GetEnumerator()IEnumerable.GetEnumerator() peut appeler le même code sous-jacent que IEnumerable, il n'est pas aussi fortement typé (renvoie un objet au lieu d'un IEnumerator fortement typé).

0

Pour mettre en œuvre la deuxième interface, faire une mise en œuvre explicite qui appelle simplement la mise en œuvre implicite l'interface générique. Quelque chose comme

class FooCollection : IEnumerable<Foo>, IEnumerable 
{ 
    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 

    public IEnumerator<Foo> GetEnumerator() 
    { 
     // return enumerator 
    } 
} 

Edit: Héritant de IEnumerable est redondant, mais cette réponse montre que les deux interfaces doivent être mises en œuvre lorsque vous héritez IEnumerable<T>, puisque IEnumerable<T> dérive de IEnumerable.

+0

-1: IEnumerable implémente déjà IEnumerable. – x0n

+0

@ x0n, c'est en partie un bon point, mon code est redondant dans la partie déclaration d'héritage de l'interface, mais il montre ce qui se passe. L'implémentation de l'interface générique nécessite la mise en œuvre de l'interface non générique. Pour être précis, cependant, 'IEnumerable ' n'implémente pas * 'IEnumerable'. Ça ne peut pas. –

+0

Je ne voulais pas vous renvoyer un point rétrospectivement - un simple commentaire aurait suffi. Je vais l'inverser. mise à jour: je ne peux pas inverser le score sauf si vous éditez votre question pour corriger la redondance ;-) – x0n

1

Il vous suffit de définir le générique (qui retourne la chaîne dans mon exemple), puis dire la méthode GetEnumerator non générique pour appeler le GetEnumerator générique (qui retourne Object.)

class Foo : IEnumerable<string> 
{ 
    public IEnumerator<string> GetEnumerator() 
    { 
     foreach (string value in new[] { "a", "b", "c" }) 
     { 
      yield return value; 
     } 
    } 

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

non générique IEnumerable interface est utilisé pour la rétrocompatibilité, il fournit également très utile pour accéder à l'interface générique IEnumerable de façon non générique.

Vous ne pouvez implémenter que IEnumerable.membre GetEnumerator, et juste mettre en œuvre une autre interface explicity comme

IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); /*generic method call*/ } 
1

Le second est pour le code écrit pour .NET version 1.1, qui ne comprennent pas les médicaments génériques.

En général, vous avez juste retourner la valeur du GetEnumerator générique()

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

En général, vous ne devriez pas avoir besoin de mettre en œuvre IEnumerable vous plus. il existe de nombreuses classes intégrées dans le cadre qui mettent en œuvre cette interface est de différentes manières de satisfaire 99% de vos besoins. Cependant, si vous le souhaitez, la méthode IEnumerable, GetEnumerator() est celle qui retournera un objet IEnumerator à un client appelant foreach. Cet objet Ienumerator est l'objet qui garde la trace de l'élément de la collection. suivant "un à être retourné quand le foreach" itère ". Pour que cela fonctionne, vous devez définir une classe qui sera celle recenseur (Il doit mettre en œuvre IEnumerator ou génériquement IEnumerator)

À titre d'exemple (pour un PersonCollection)

public IEnumerator GetEnumerator() { return new myTypeEnumerator(this); } 
public class myTypeEnumerator : IEnumerator 
{ 
    int nIndex; 
    PersonCollection pers; 
    public myTypeEnumerator(PersonCollection myTypes) 
    { pers = myTypes; nIndex = -1; } 
    public bool MoveNext() { return (++nIndex < pers.alPers.Count); } 
    public object Current { get { return (pers[nIndex]); } } 
    public void Reset() { nIndex = -1; } 
} 

La seule différence entre cette et la version générique est que la version générique est fortement typée:

public IEnumerator<T> GetEnumerator() { return new myTypeEnumerator<T>(this); } 
public class myTypeEnumerator<T> : IEnumerator<T> 
{ 
    int nIndex; 
    IList<T> tList; 
    public myTypeEnumerator(IList<T> listOfTs) 
    { 
     tList = listOfTs; 
     nIndex = -1; 
    } 
    public bool MoveNext() { return (++nIndex < tList.Count); } 
    public T Current { get { return (tList[nIndex]); } } 
    public void Reset() { nIndex = -1; } 
}