IEnumerable的多个枚举器

时间:2010-08-25 14:58:29

标签: c# .net ienumerable ienumerator

我有一个定制的集合,里面有许多对象生成模式。
它可以一次生成所有内容,一个对象或一次生成N个对象 我希望可以选择在运行时在生成的实现之间切换,甚至可以创建新的实现 我正在寻找具有这种语法的东西:

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

我的问题是:
我不知道EnumerateAs()会返回什么?我假设它是IEnumerator,但它仍然是我列表的枚举器吗? LazyEnumerator是否继承自IEnumerator?
怎么知道myCollection?

3 个答案:

答案 0 :(得分: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>>替换策略类,但上述内容最接近您所需的语法。

答案 1 :(得分: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&lt; T&gt;。来自封装的对象。顺便说一下,可以将泛型与标记类一起使用,以避免必须为枚举的每个变体手动定义新的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。

答案 2 :(得分: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

非常灵活。