2013-01-16 14 views
5

Powiel możliwe:
Implementing C# IEnumerable<T> for a LinkedList classWdrażanie IEnumerable do mojego obiektu

Po poszukiwaniach w internecie na kilka godzin teraz ja wciąż nie mogę zrozumieć, jak IEnumerable/IEnumerator działa i jak go wdrożyć .

Skonstruowałem prosty od zera LinkedList, ale teraz chcę zaimplementować IEnumerable, abym mógł go wyłączyć. Jak mogę to zrobić?

class Program 
{ 
    LL myList = new LL(); 

    static void Main() 
    { 
     var gogo = new Program(); 
    } 
    public Program() 
    { 

     myList.Add("test"); 
     myList.Add("test1"); 

     foreach (var item in myList) //This doesn't work because I havn't implemented Ienumerable 
      Console.WriteLine(item); 

     Console.Read(); 
    } 
} 


class LL 
{ 

    private LLNode first; 

    public void Add(string s) 
    { 
     if (this.first == null) 
      this.first = new LLNode() { Value = s }; 
     else 
     { 
      var node = this.first; 
      while (node.Next != null) 
       node = node.Next; 

      node.Next = new LLNode() { Value = s }; 
     } 
    } 


class LLNode 
{ 
    public string Value { get; set; } 
    public LLNode Next { get; set; } 
} 
+4

Czy jesteś pewien, że próbowałeś? – Nahum

+1

[tutaj] (http://codebetter.com/davidhayden/2005/03/08/implementing-ienumerable-and-ienumerator-on-your-custom-objects/) jest * nie jest dobrym samouczkiem dotyczącym implementacji 'IEnumerable' na niestandardowa klasa. [Tutaj] (http://www.codeproject.com/Articles/474678/A-Beginners-Tutorial-on-Implementing-Ynumerable-I) jest lepszy. – NominSim

+0

Zauważ, że technicznie nie * nie trzeba * wdrażać 'IEnumerable' aby użyć twojej klasy z' foreach'-loop ... – sloth

Odpowiedz

3

Co trzeba zrobić, to:

(1) Dokonać klasa zaimplementować IEnumerable <T> gdzie T typ wymienionych elementów. (W twoim przypadku wygląda na to, że byłby to LLNode).

(2) Napisz publiczny numerator <T> Narzędzie do sprawdzania numerów. Wprowadź go za pomocą słowa kluczowego "yield".

(3) Dodaj metodę IEnumerator IEnumerable.GetEnumerator() i po prostu wróć GetEnumerator().

Poniższy kod powinien to wyjaśnić. Gdzie mam <int>, powinieneś umieścić <LLNode>, zakładając, że jest to poprawny typ.

using System; 
using System.Collections; 
using System.Collections.Generic; 

namespace Demo 
{ 
    internal class Program 
    { 
     private static void Main() 
     { 
      var test = new MyDemo(); 

      foreach (int item in test) 
      { 
       Console.WriteLine(item); 
      } 
     } 
    } 

    public class MyDemo: IEnumerable<int> 
    { 
     public IEnumerator<int> GetEnumerator() 
     { 
      // Your implementation of this method will iterate over your nodes 
      // and use "yield return" to return each one in turn. 

      for (int i = 10; i <= 20; ++i) 
      { 
       yield return i; 
      } 
     } 

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

Zmodyfikowałbym twój kod, żeby zrobić to poprawnie, ale kod, który wysłałeś, nie będzie się kompilował.

[EDIT]

Teraz zaktualizowaniu kodu, widzę, że chcesz wyliczyć wartości. Oto kompletny kod:

using System; 
using System.Collections; 
using System.Collections.Generic; 

namespace Demo 
{ 
    internal class Program 
    { 
     private LL myList = new LL(); 

     private static void Main() 
     { 
      var gogo = new Program(); 
     } 

     public Program() 
     { 
      myList.Add("test"); 
      myList.Add("test1"); 

      foreach (var item in myList) // This now works. 
       Console.WriteLine(item); 

      Console.Read(); 
     } 
    } 


    internal class LL: IEnumerable<string> 
    { 
     private LLNode first; 

     public void Add(string s) 
     { 
      if (this.first == null) 
       this.first = new LLNode 
       { 
        Value = s 
       }; 
      else 
      { 
       var node = this.first; 
       while (node.Next != null) 
        node = node.Next; 

       node.Next = new LLNode 
       { 
        Value = s 
       }; 
      } 
     } 

     public IEnumerator<string> GetEnumerator() 
     { 
      for (var node = first; node != null; node = node.Next) 
      { 
       yield return node.Value; 
      } 
     } 

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

     private class LLNode 
     { 
      public string Value { get; set; } 
      public LLNode Next { get; set; } 
     } 
    } 
} 
+0

Spróbuj skompilować go teraz, bez pętli foreach i WriteLite. –

+0

Dzięki to działa teraz. Teraz to zbadam. –

6

To naprawdę nie jest takie trudne. Aby zaimplementować IEnumerable wystarczy zaimplementować metodę GetEnumerator.

Aby to zrobić, musisz utworzyć kolejną klasę, która implementuje IEnumerator. Wdrożenie IEnumeratora jest dość łatwe. Generalnie przekażesz odwołanie do swojej kolekcji podczas tworzenia modułu wyliczającego (w narzędziu GetEnumerator), a moduł wyliczający będzie śledził, który element jest bieżącym elementem. Następnie dostarczy MoveNext, który po prostu zmienia Current na następny element (i zwraca wartość false, jeśli znajduje się na końcu listy) i Reset, który właśnie ustawia Current z powrotem na przed pierwszym węzłem.

więc w bardzo szerokich, niesprawdzonych pod względem kodu, trzeba coś takiego:

public class MyLinkedListEnumerator : IEnumerator 
{ 
    private LL myList; 
    private LLNode current; 

    public object Current 
    { 
     get { return current; } 
    } 

    public MyLinkedListEnumerator(LL myList) 
    { 
     this.myList = myList; 
    } 

    public bool MoveNext() 
    { 
     if (current == null) { 
      current = myList.first; 
     } 
     else { 
      current = current.Next; 
     } 
     return current != null; 
    } 

    public void Reset() 
    { 
     current = null; 
    } 
} 
+0

Aby to podkreślić, C# bardzo ci to pomaga, jeśli sam stworzysz metodę 'GetEnumerator()' za pomocą instrukcji 'yield' itd. – NominSim

+0

Otrzymuję: Błąd Niespójny dostęp: typ parametru" xx.LL " "jest mniej dostępny niż metoda" xx.MyLinkedListEnumerator.MyLinkedListEnumerator (xx.LL) "\t C: \\ xx \ Program.cs error –

+0

@Ben: To prawdopodobnie dlatego, że twoja klasa" LL "jest prywatna. Oznacz to jako publiczne. –