2

内部にオブジェクト生成の多くのモードがあるカスタムメイドのコレクションがあります。
一度に 1 つのオブジェクトまたは一度に N 個のオブジェクトを生成できます。
実行時に生成の実装を切り替えたり、新しいものを作成したりするオプションが欲しいです。
私はこの種の構文で何かを探しています:

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

私の問題は次のとおりです。
何が返されるのかわかりませんEnumerateAs()か?私はそれが IEnumerator だと仮定していますが、それでも私のリストの列挙子になりますか?
LazyEnumerator は IEnumerator を継承していますか?
myCollection をどのように認識していますか?

4

3 に答える 3

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
    }
}

戦略クラスを単純な strategyFunc<MyCollection, IEnumerable<T>>に置き換えることもできますが、上記は目的の構文に最もよく一致することに注意してください。

于 2010-08-25T15:18:19.637 に答える
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

非常に柔軟です。

于 2012-06-14T18:01:46.377 に答える
0

関数 GetEnumeratorInFirstStyle、GetEnumeratorInSecondStyle などを作成することから始めて (もちろん、アプリケーションに適した名前を使用してください)、次のような新しい構造を作成することをお勧めします (vb 構文の例ですが、C# に簡単に変換できるはずです)。

クラス enumTest
    関数 GetEnumeratorInFirstStyle() As IEnumerator(Of Integer)
        Return Enumerable.Empty(Of Integer)() ' 実際のコードはもっと良いことをするでしょう
    終了機能
    プライベート構造体 FirstStyleEnumerable
        IEnumerable(Of Integer) を実装します

        プライベート myEnumTest As enumTest

        Public Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of Integer) System.Collections.Generic.IEnumerable(Of Integer).GetEnumerator を実装
            myEnumTest.GetEnumeratorInFirstStyle を返します
        終了機能

        パブリック関数 GetEnumerator1() System.Collections.IEnumerator として実装 System.Collections.IEnumerable.GetEnumerator
            myEnumTest.GetEnumeratorInFirstStyle を返します
        終了機能

        Sub New(ByVal newEnumTest As enumTest)
            myEnumTest = newEnumTest
        サブ終了
    末端構造
    Public ReadOnly プロパティ AsFirstStyleEnumerable As IEnumerable(Of Integer)
        得る
            新しい FirstStyleEnumerable(Me) を返す
        エンドゲット
    End プロパティ
クラス終了

クラスではなく構造体が使用されることに注意してください。クラスを使用すると、新しいヒープ オブジェクトを作成する必要があり、そのアクセスに余分なレベルの間接性が追加されるためです。構造体の本当の目的は、カプセル化されたオブジェクトとは「異なる」IEnumerable<T> を実装できるようにすることです。ところで、列挙のバリエーションごとに新しい FirstStyleEnumerator 構造体を手動で定義する必要がないように、マーカー クラスでジェネリックを使用することは可能です。ただし、それがよりクリーンになるか、より混乱するかはわかりません。

インターフェース IQualifiedEnumerable(Of T, U)
    関数 GetEnumerator() As IEnumerable(Of U)
終了インターフェイス

構造体 QualifiedEnumerableWrapper(Of T, U)
    IEnumerable(Of U) を実装します
    Private myEnumerable As IQualifiedEnumerable(Of T, U)

    Public Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of U) 実装 System.Collections.Generic.IEnumerable(Of U).GetEnumerator
        myEnumerable.GetEnumerator を返します
    終了機能

    パブリック関数 GetEnumerator1() System.Collections.IEnumerator として実装 System.Collections.IEnumerable.GetEnumerator
        myEnumerable.GetEnumerator を返します
    終了機能

    Sub New(ByVal newEnumerable As IQualifiedEnumerable(Of T, U))
        myEnumerable = newEnumerable
    サブ終了
末端構造

クラス EnumTest2
    IQualifiedEnumerable(Of FirstEnumerationStyle, Integer) を実装します
    IQualifiedEnumerable(Of SecondEnumerationStyle, Integer) を実装します

    Private Class FirstEnumerationStyle ' ジェネリックのマーカー クラス
    クラス終了
    プライベート クラス SecondEnumerationStyle
    クラス終了

    Private Function GetFirstStyleEnumerator() As System.Collections.Generic.IEnumerable(Of Integer) IQualifiedEnumerable(Of FirstEnumerationStyle, Integer).GetEnumerator を実装
        Enumerable.Empty(Of Integer)() を返す
    終了機能

    プライベート関数 GetSecondStyleEnumerator() は System.Collections.Generic.IEnumerable(Of Integer) として IQualifiedEnumerable(Of SecondEnumerationStyle, Integer).GetEnumerator を実装します
        Enumerable.Empty(Of Integer)() を返す
    終了機能

    Public ReadOnly プロパティ AsFirstStyleEnumerable As IEnumerable(Of Integer)
        得る
            新しい QualifiedEnumerableWrapper(Of FirstEnumerationStyle, Integer) を返します
        エンドゲット
    End プロパティ

    Public ReadOnly プロパティ AsSecondStyleEnumerable As IEnumerable(Of Integer)
        得る
            新しい QualifiedEnumerableWrapper(Of SecondEnumerationStyle, Integer) を返します
        エンドゲット
    End プロパティ
クラス終了

ここで、インターフェースと構造体の定義は完全に汎用的です。列挙の各追加メソッドをクラスに追加するには、その列挙子を返す関数と、適切な型の QualifiedEnumerableWrapper を返すプロパティを追加する必要があります。

于 2011-04-03T17:46:56.530 に答える