почему в многомерных массивах c # не реализован ienumerable <t>?

<p>я только что заметил, что многомерный массив в c # не реализует <code>ienumerable<t></code>, в то время как он реализует <code>ienumerable</code>. для одномерных массивов реализованы и <code>ienumerable<t></code>, и <code>ienumerable</code>.</p><p>почему эта разница? если многомерный массив <code>ienumerable</code>, он также должен реализовывать универсальную версию? я заметил это, потому что я пытался использовать метод расширения в многомерном массиве, который завершается неудачей, если вы не используете <code>cast<t></code> или аналогичный; так что я определенно вижу аргумент для реализации многомерных массивов <code>ienumerable<t></code>.</p><p>чтобы прояснить мой вопрос в коде, я ожидал бы, что следующий код будет печатать <code>true</code> четыре раза, в то время как он фактически печатает <code>true</code>, <code>false</code>, <code>true</code>, <code>true</code>:</p><pre><code>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); </code></pre>

<p>clr имеет два различных типа массивов: <em>векторы</em>, которые гарантированно будут одномерными с нижней границей 0, и более общие массивы, которые могут иметь ненулевые границы и ранг, отличный от 0.</p><p>из раздела 8.9.1 спецификации cli:</p><blockquote> <p>кроме того, созданный вектор с типом элемента t реализует интерфейс <code>system.collections.generic.ilist<u></code> (§8.7), где u: = t.</p> </blockquote><p>я должен сказать, что это кажется довольно странным для меня. учитывая, что он уже реализует <code>ienumerable</code>, я не понимаю, почему он не должен реализовывать <code>ienumerable<t></code>. не было бы особого смысла в реализации <code>ilist<t></code>, но простой общий интерфейс был бы в порядке.</p><p>если вы хотите этого, вы можете либо вызвать <code>cast<t></code> (если вы используете .net 3.5), либо написать свой собственный метод для перебора массива. чтобы избежать приведения, вы должны написать свой собственный метод, который бы находил нижнюю/верхнюю границы каждого измерения и таким образом выбирал вещи. не очень приятно.</p>

<p>существует обходной путь: вы можете преобразовать любой многомерный массив в ienumerable.</p><pre><code>public static class arrayextensions { public static ienumerable<t> toenumerable<t>(this array target) { foreach (var item in target) yield return (t)item; } } </code></pre>

<p>многомерные массивы являются <em>не</em> массивами для целей иерархии наследования. они совершенно отдельный тип. кроме того, этот тип не имеет хорошей поддержки со стороны платформы по двум возможным причинам:</p><ul> <li>это не очень полезно. единственное реальное использование для многомерных массивов - это матрицы. почти для всего остального лучше подходят другие структуры данных (например, неровные массивы).</li> <li>нетрудно разработать общие, полезные методы для этих структур.</li> </ul><p>в случае <code>ienumerable</code>, как это должно быть реализовано, то есть, в каком порядке должны перечисляться элементы? там нет порядка, присущего многомерным массивам.</p>

<p>ограниченные нулями одномерные массивы реализуют и <code>ienumerable</code>, и <code>ienumerable<t></code>, но, к сожалению, многомерные массивы реализуют только <code>ienumerable</code>. "обходной путь" @jader dias действительно преобразует многомерный массив в <code>ienumerable<t></code>, но с огромными затратами: каждый элемент массива будет упакован.</p><p>вот версия, которая не будет вызывать бокс для каждого элемента:</p><pre><code>public static class arrayextensions { public static ienumerable<t> toenumerable<t>(this t[,] target) { foreach (var item in target) yield return item; } } </code></pre>

<p>зубчатые массивы также не поддерживают <code>ienumerable<int></code>, потому что многомерные структуры на самом деле не являются массивом типа, они являются массивом массива типа:</p><pre><code>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); </code></pre><p>печатает правда, правда, правда, правда.</p><p><strong>примечание</strong>: <code>int[,]</code> не является <code>ienumerable<int[]></code>, это по причинам, указанным в другом ответе, а именно, нет общего способа узнать, какое измерение перебирать. с неровными массивами не так много места для интерпретации, потому что синтаксис достаточно ясен, поскольку он представляет собой массив массивов.</p>

<p>думай наоборот. 2d массив уже существует. просто перечислите это. создайте двумерный массив с оценкой и местом начального массива или отметок, включая повторяющиеся значения.</p><pre><code>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(); </code></pre><p>результаты:</p><pre><code>score place 100 1 99 2 90 3 50 4 40 5 35 6 34 7 31 8 20 9 20 10 15 11 </code></pre>