web-dev-qa-db-ja.com

IEnumeratorを汎用IEnumeratorに変換する最良の方法は何ですか?

C#.NET 3.5でカスタムConfigurationHandlerのカスタムConfigurationElementCollectionを作成していて、IEnumeratorを汎用IEnumeratorとして公開したいと考えています。

これを達成するための最良の方法は何でしょうか?

私は現在コードを使用しています:

 public new IEnumerator <GenericObject> GetEnumerator()
 {
 var list = new List(); 
 var baseEnum = base.GetEnumerator(); 
 while(baseEnum.MoveNext())
 {
 var obj = baseEnum.Current as GenericObject; 
 if(obj!= null)
 list.Add (obj); 
} 
 return list.GetEnumerator(); 
} 

乾杯

31
zonkflut

フレームワークには何もないと思いますが、簡単に書くことができます。

_IEnumerator<T> Cast<T>(IEnumerator iterator)
{
    while (iterator.MoveNext())
    {
        yield return (T) iterator.Current;
    }
}
_

LINQから_Enumerable.Cast<T>_を呼び出してから、結果に対してGetEnumerator()を呼び出すのは魅力的ですが、クラスがすでに_IEnumerable<T>_を実装していて、Tが値型である場合、ノーオペレーションとして機能するため、GetEnumerator()呼び出しは再帰し、StackOverflowExceptionをスローします。 fooが間違いなく異なるオブジェクト(これはこのオブジェクトに委任されない)である場合はreturn foo.Cast<T>.GetEnumerator();を使用しても安全ですが、それ以外の場合はおそらく最善です。上記のコードを使用します。

52
Jon Skeet

IEnumerable<T>はすでにIEnumerableから派生しているため、変換を行う必要はありません。単純にキャストすることができます...実際には、キャストは必要ありません。

IEnumerable<T> enumerable = GetGenericFromSomewhere();
IEnumerable sadOldEnumerable = enumerable;
return sadOldEnumerable.GetEnumerator();

LINQを使用すると、逆の方向に進むことはそれほど難しくありません。

var fancyEnumerable = list.OfType<GenericObject>();
return fancyEnumerable.GetEnumerator();
3
Paul Alexander

私は、コメントのいくつかが言及されているのと同じスタックオーバーフローの問題に遭遇していました。私の場合、GetEnumerator呼び出しをbase.GetEnumeratorに対して行う必要があるという事実が原因でした。そうしないと、独自のGetEnumerator再定義内でループします。

これは、スタックオーバーフローをスローしていたコードです。 foreachステートメントを使用すると、オーバーロードしようとしているのと同じGetEnumerator関数が呼び出されます。

public new IEnumerator<T> GetEnumerator()
{
    foreach (T type in this)
    {
        yield return type;
    }
}

リストホルダーを使用する必要がないため、元の投稿の簡略版になりました。

public class ElementCollection<T> : ConfigurationElementCollection, IList<T>
    ...
    public new IEnumerator<T> GetEnumerator()
    {
        var baseEnum = base.GetEnumerator();
        while (baseEnum.MoveNext())
        {
            yield return baseEnum.Current as T;
        }
    }
    ...
}
1
VeV

_OfType<T>_および_Cast<T>_を使用できます。

_public static IEnumerable Digits()
{
    return new[]{1, 15, 68, 1235, 12390, 1239};
}

var enumerable = Digits().OfType<int>();
foreach (var item in enumerable)
    // var is here an int. Without the OfType<int(), it would be an object
    Console.WriteLine(i);
_

_IEnumerator<T>_の代わりに_IEnumerable<T>_を取得するには、GetEnumerator()を呼び出すだけです。

_var enumerator = Digits().OfType<int>().GetEnumerator();
_
0
Svish

これは私にとってはうまくいきます。

IEnumerator<DataColumn> columnEnumerator = dt.Columns.Cast<DataColumn>().GetEnumerator();
0
DenverYogi