C#の多次元配列はIEnumerable<T>
を実装していませんが、IEnumerable
は実装しています。 1次元配列の場合、IEnumerable<T>
とIEnumerable
の両方が実装されています。
なぜこの違いがあるのですか?多次元配列がIEnumerable
の場合、確かにジェネリックバージョンも実装する必要がありますか?多次元配列で拡張メソッドを使用しようとしたため、Cast<T>
などを使用しないと失敗するため、このことに気付きました。多次元配列にIEnumerable<T>
を実装させるための議論は間違いなくわかります。
コードで私の質問を明確にするために、私は次のコードがtrue
、true
、false
、true
を実際に出力するのに対し、true
を4回出力することを期待します。
int[] singleDimensionArray = new int[10];
int[,] multiDimensional = new int[10, 10];
Debug.WriteLine(singleDimensionArray is IEnumerable<int>);
Debug.WriteLine(multiDimensional is IEnumerable<int>);
Debug.WriteLine(singleDimensionArray is IEnumerable);
Debug.WriteLine(multiDimensional is IEnumerable);
CLRには2種類の配列があります。vectorsは下限が0の1次元であることが保証されており、より一般的な配列は非ゼロの境界と0以外のランクを持つことができます。
CLI仕様のセクション8.9.1から:
さらに、エレメントタイプTで作成されたベクターは、インターフェイス
System.Collections.Generic.IList<U>
(§8.7)を実装します。ここで、U:= Tです。
私にはかなり奇妙に思えます。 IEnumerable
がすでに実装されていることを考えると、IEnumerable<T>
を実装してはならない理由がわかりません。 IList<T>
を実装することはそれほど意味がありませんが、単純な汎用インターフェースで十分です。
これが必要な場合は、Cast<T>
(.NET 3.5を使用している場合)を呼び出すか、独自のメソッドを記述して配列を反復処理できます。キャストを回避するには、各次元の下限/上限を見つけ、その方法でフェッチする独自のメソッドを記述する必要があります。ひどく快適ではありません。
回避策があります:多次元配列をIEnumerableに変換できます
public static class ArrayExtensions
{
public static IEnumerable<T> ToEnumerable<T>(this Array target)
{
foreach (var item in target)
yield return (T)item;
}
}
多次元配列は、継承階層を目的としたnot配列です。それらは完全に別のタイプです。さらに、このタイプには、2つの考えられる理由により、フレームワークからの適切なサポートがありません。
IEnumerable
の場合、これをどのように実装する必要がありますか、つまり、要素を列挙する順序は?多次元配列に固有の順序はありません。
ゼロバインドの1次元配列はIEnumerable
とIEnumerable<T>
の両方を実装しますが、多次元配列は残念ながらIEnumerable
のみを実装します。 @Jader Diasによる「回避策」は確かに多次元配列をIEnumerable<T>
に変換しますが、コストが非常に高くなります。配列のすべての要素がボックス化されます。
すべての要素にボクシングが発生しないバージョンは次のとおりです。
public static class ArrayExtensions
{
public static IEnumerable<T> ToEnumerable<T>(this T[,] target)
{
foreach (var item in target)
yield return item;
}
}
ギザギザの配列もIEnumerable<int>
をサポートしていません。多次元構造は実際には型の配列ではないため、型の配列の配列です。
int[] singleDimensionArray = new int[10];
int[][] multiJagged = new int[10][];
Debug.WriteLine(singleDimensionArray is IEnumerable<int>);
Debug.WriteLine(multiJagged is IEnumerable<int[]>);
Debug.WriteLine(singleDimensionArray is IEnumerable);
Debug.WriteLine(multiJagged is IEnumerable);
True、true、true、trueを出力します。
注:int[,]
はIEnumerable<int[]>
ではありません。これは、他の回答で指定されている理由によるものです。つまり、どのディメンションを反復するかを知る一般的な方法はありません。ギザギザの配列では、配列の配列であることについて構文がかなり明確であるため、解釈の余地はあまりありません。
逆に考えます。 2D配列は既に存在します。列挙するだけです。重複する値を含む、最初の配列またはマークのスコアと場所を含む2D配列を作成します。
int[] secondmarks = {20, 15, 31, 34, 35, 50, 40, 90, 99, 100, 20};
IEnumerable<int> finallist = secondmarks.OrderByDescending(c => c);
int[,] orderedMarks = new int[2, finallist.Count()];
Enumerable.Range(0, finallist.Count()).ToList().ForEach(k => {orderedMarks[0, k] = (int) finallist.Skip(k).Take(1).Average();
orderedMarks[1, k] = k + 1;});
Enumerable.Range(0, finallist.Count()).Select(m => new {Score = orderedMarks[0, m], Place = orderedMarks[1, m]}).Dump();
結果:
Score Place
100 1
99 2
90 3
50 4
40 5
35 6
34 7
31 8
20 9
20 10
15 11