Многомерные массивы не реализуют IEnumerable <T>или нет? - PullRequest
4 голосов
/ 06 апреля 2009

По причинам, которые я до сих пор не понимаю ( см. Этот вопрос ), многомерные массивы в CLR не реализуют IEnumerable<T>. Таким образом, следующее не компилируется:

var m = new int[2,2] {{1, 2}, {3, 4}};
var q = from e in m select e;

Тогда почему этот прекрасно работает в VB.NET ?

Sub Main()
    Dim m(,) As Integer = {{1, 2}, {3, 4}}
    Dim q = From e In m Select e

    For Each i In q
        Console.WriteLine(i)
    Next
End Sub

Обновление:

Следующий код работает, потому что компилятор C # заменяет циклы foreach на for для прохождения каждого измерения.

foreach(var e in m)
    Console.WriteLine(e);

становится

int[,] numArray3 = new int[,] { { 2, 2 }, { 3, 3 } };
int upperBound = numArray3.GetUpperBound(0);
int num4 = numArray3.GetUpperBound(1);
for (int i = numArray3.GetLowerBound(0); i <= upperBound; i++)
{
    for (int j = numArray3.GetLowerBound(1); j <= num4; j++)
    {
        int num = numArray3[i, j];
        Console.WriteLine(num);
    }
}

Ответы [ 4 ]

8 голосов
/ 06 апреля 2009

Запрос работает в VB.Net, потому что он преобразуется в

IEnumerable<object> q = m.Cast<object>().Select<object, object>(o => o);

Это работает, потому что вы можете вызвать Cast<TResult> () на IEnumerable, что [*,*] реализует.

Запрос LINQ не работает в C # из-за разного подхода, принятого дизайнерами C # и VB.Net. VB.Net использует более сложный подход, исправляет вашу ошибку и конвертирует IEnumerable в IEnumerable<object>, чтобы его можно было использовать.

В C # вы можете смоделировать это с помощью

var q = from e in m.Cast<object>() select e;
4 голосов
/ 06 апреля 2009

Есть две причины, по которым они не реализуют это изначально в C #:

  • Есть несколько способов сделать это. Хотите ли вы каждую «клетку» или каждую «строку»? А как вы определяете 'row': [], IEnumerable, other? Что если есть более двух измерений? Как только они выберут один путь, армия разработчиков скажет им, что они должны были сделать это по-другому.
  • Благодаря блокам итераторов и ключевому слову yield так просто реализовать свой собственный, соответствующий вашим потребностям на тот момент. Конечно, это конструкция C #, но это не , что намного сложнее в VB.
2 голосов
/ 23 мая 2009

Совет: вместо Cast () используйте типизированную переменную диапазона


Самуил заявил:

В C # вы можете смоделировать это с помощью

var q = from e in m.Cast<object>() select e;
// q is of type IEnumerable<object>

, что, конечно, правильно, если имитировать VB в C #, но вы потеряете информацию о вашем типе. Вместо этого гораздо проще и, как оказалось, немного лучше читаемо просто объявить переменную диапазона.

Следующие компиляторы работают лучше, безопасны от типов и не теряют информацию о типах:

var m = new int[2, 2] { { 1, 2 }, { 3, 4 } };
var q = from int e in m select e;
// q is of type IEnumerable<int>

В исходном предложении у вас будет IEnumerable<object>, с помощью int e вы измените его на IEnumerable<int>, что имеет свои преимущества.

2 голосов
/ 06 апреля 2009

Страница MSDN для массива включает следующее:

Важное примечание: В .NET Framework версии 2.0 класс Array реализует универсальные интерфейсы System.Collections.Generic.IList , System.Collections.Generic.ICollection и System.Collections.Generic.IEnumerable . Реализации предоставляются массивам во время выполнения,

Обратите внимание на последние слова в цитате ... кажется, что это поколение не происходит для многомерных массивов (поэтому ошибка документации).

Но, как отмечали другие, что бы было T? Хороший случай может быть сделан для T[] (или, в наши дни с LINQ, IEnumerable<T>).

В конце концов, если вы хотите перебрать все элементы массива, просто используйте расширение IEnumerable и Cast . В противном случае легко написать свой собственный.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...