2010-08-25 101 views
2

我有一個定製的集合,它有許多對象生成模式。
它可以產生一切,一次一個對象或一次N個對象。
我希望可以在運行時切換生成實現,甚至可以創建新實例。
我在尋找的東西用這種語法:IEnumerable的多個枚舉器

foreach(var obj in myCollection.EnumerateAs(new LazyEnumerator()) 
{ 
    // ... 
} 

我的問題是:
我不知道該怎麼做EnumerateAs()回報呢?我假設它是IEnumerator,但它仍然是我的列表的枚舉?
LazyEnumerator是否繼承自IEnumerator?
它是如何知道myCollection的?

+0

爲什麼downvote? – 2010-08-27 02:47:28

回答

5

EnumerateAs()的返回值應該是IEnumerable<T>,其中T是集合中包含的對象的類型。我建議閱讀更多關於yield return的信息,因爲這可以幫助您瞭解枚舉是如何工作的。沒有提供枚舉「策略」的默認類,但是您可以通過以各種方式對底層集合使用yield return來輕鬆實現類似的內容。

從您的問題中確切不清楚枚舉策略如何與您的集合類進行交互。它看起來像你可能會喜歡的東西后:

public interface IEnumerationStrategy<TCollection, T> 
{ 
    IEnumerable<T> Enumerate(TCollection source); 
} 

public class Quark {} 

public class MyCollection 
{ 
    public IEnumerable<Quark> EnumerateAs(IEnumerationStrategy<MyCollection, Quark> strategy) 
    { 
     return strategy.Enumerate(this); 
    } 

    //Various special methods needed to implement stategies go here 
} 

public class SpecialStrategy : IEnumerationStrategy<MyCollection, Quark> 
{ 
    public IEnumerable<Quark> Enumerate(MyCollection source) 
    { 
     //Use special methods to do custom enumeration via yield return that depends on specifics of MyCollection 
    } 
} 

請注意,您也可以用一個簡單的策略Func<MyCollection, IEnumerable<T>>更換策略類,但上述最符合您需要的語法。

+0

你能告訴我一個簡單的代碼示例嗎? EnumerateAs將如何看起來像? 產量不應該在LazyEnumerator本身中嗎? 這意味着我必須將列表傳遞給LazyEnumerator,對吧? – 2010-08-25 15:27:06

+0

那麼枚舉策略不會繼承自IEnumerator ? 感謝您的提示。我將創建兩個重載,所以它也將接受代表:) – 2010-08-25 15:35:46

+0

這實現了您的問題的目標,但我的感覺是,這可能比您需要更復雜。這些策略與您的自定義MyCollection類緊密耦合,因此擴展性好處不大,您也可以爲集合製作不同的枚舉方法。如果你有幾個特殊集合的共同接口(這聽起來像是他們真的比生成集合更多),並希望通過標準接口在它們之間共享策略,這將主要是有益的。 – 2010-08-25 15:52:56

0

我建議你先創建函數GetEnumeratorInFirstStyle,GetEnumeratorInSecondStyle等(當然使用適合你的應用的名字),然後創建一些新的結構(例如在vb語法中,但應該很容易轉換爲C#):

 
Class enumTest 
    Function GetEnumeratorInFirstStyle() As IEnumerator(Of Integer) 
     Return Enumerable.Empty(Of Integer)() ' Real code would do something better 
    End Function 
    Private Structure FirstStyleEnumerable 
     Implements IEnumerable(Of Integer) 

     Private myEnumTest As enumTest 

     Public Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of Integer) Implements System.Collections.Generic.IEnumerable(Of Integer).GetEnumerator 
      Return myEnumTest.GetEnumeratorInFirstStyle 
     End Function 

     Public Function GetEnumerator1() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator 
      Return myEnumTest.GetEnumeratorInFirstStyle 
     End Function 

     Sub New(ByVal newEnumTest As enumTest) 
      myEnumTest = newEnumTest 
     End Sub 
    End Structure 
    Public ReadOnly Property AsFirstStyleEnumerable As IEnumerable(Of Integer) 
     Get 
      Return New FirstStyleEnumerable(Me) 
     End Get 
    End Property 
End Class 

注意的結構而不是使用一個類,因爲使用類將需要創建一個新的堆對象,並添加間接到其接入額外的水平;該結構的真正目的是允許它從封裝對象實現「不同的」IEnumerable <T>。順便說一句,有可能使用具有標記類的泛型來避免爲每個枚舉變體手動定義一個新的FirstStyleEnumerator結構。不過,我不確定這是否會更乾淨或更混亂。

 
Interface IQualifiedEnumerable(Of T, U) 
    Function GetEnumerator() As IEnumerable(Of U) 
End Interface 

Structure QualifiedEnumerableWrapper(Of T, U) 
    Implements IEnumerable(Of U) 
    Private myEnumerable As IQualifiedEnumerable(Of T, U) 

    Public Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of U) Implements System.Collections.Generic.IEnumerable(Of U).GetEnumerator 
     Return myEnumerable.GetEnumerator 
    End Function 

    Public Function GetEnumerator1() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator 
     Return myEnumerable.GetEnumerator 
    End Function 

    Sub New(ByVal newEnumerable As IQualifiedEnumerable(Of T, U)) 
     myEnumerable = newEnumerable 
    End Sub 
End Structure 

Class EnumTest2 
    Implements IQualifiedEnumerable(Of FirstEnumerationStyle, Integer) 
    Implements IQualifiedEnumerable(Of SecondEnumerationStyle, Integer) 

    Private Class FirstEnumerationStyle  ' Marker classes for generics 
    End Class 
    Private Class SecondEnumerationStyle 
    End Class 

    Private Function GetFirstStyleEnumerator() As System.Collections.Generic.IEnumerable(Of Integer) Implements IQualifiedEnumerable(Of FirstEnumerationStyle, Integer).GetEnumerator 
     Return Enumerable.Empty(Of Integer)() 
    End Function 

    Private Function GetSecondStyleEnumerator() As System.Collections.Generic.IEnumerable(Of Integer) Implements IQualifiedEnumerable(Of SecondEnumerationStyle, Integer).GetEnumerator 
     Return Enumerable.Empty(Of Integer)() 
    End Function 

    Public ReadOnly Property AsFirstStyleEnumerable As IEnumerable(Of Integer) 
     Get 
      Return New QualifiedEnumerableWrapper(Of FirstEnumerationStyle, Integer) 
     End Get 
    End Property 

    Public ReadOnly Property AsSecondStyleEnumerable As IEnumerable(Of Integer) 
     Get 
      Return New QualifiedEnumerableWrapper(Of SecondEnumerationStyle, Integer) 
     End Get 
    End Property 
End Class 

這裏,接口和結構的定義是完全通用的;將每個額外的枚舉方法添加​​到一個類中需要添加一個函數來返回它的枚舉器,並且需要一個屬性來返回適當類型的QualifiedEnumerableWrapper。

0
public class AltEnumerator : System.Collections.IEnumerable 
{ 

    private System.Collections.IEnumerator _base; 

    public AltEnumerator(System.Collections.IEnumerator _pbase) 
    { 
     _base = _pbase; 
    } 


    #region IEnumerable Members 

    public System.Collections.IEnumerator GetEnumerator() 
    { 
     return _base ; 
    } 

    #endregion 
} 

在你的類,你可以:

public AltEnumerator Iterate(IterDIrection How) 
    { 
     switch (How) 
     { 
      case TwoDimArray<T>.IterDIrection.RghtLeftTopBottom: 
       return new AltEnumerator(GetRightLeft()); 
     } 
     return new AltEnumerator(GetEnumerator()); 
    } 

    private System.Collections.IEnumerator GetRightLeft() 
    { 
     for (int cndx = PutSlotArray.GetLength(1) - 1; cndx >= 0; cndx--) 
      for (int rndx = 0; rndx < PutSlotArray.GetLength(0); rndx++) 
       if (PutSlotArray[rndx, cndx] != null) 
        yield return PutSlotArray[rndx, cndx]; 
    } 

    #region IEnumerable Members 

    public System.Collections.IEnumerator GetEnumerator() 
    { 
     foreach (T ps in PutSlotArray) 
      if (ps != null) 
       yield return ps; 
    } 

    #endregion 

非常flexable。

+0

你能解釋一下你的代碼並展示一個例子嗎? – quantum 2012-10-21 03:51:12