Por que os arrays multidimensionais C # não implementam IEnumerable ?

Acabei de notar que um array multidimensional em C # não implementa IEnumerable , enquanto implementa IEnumerable . Para matrizes unidimensionais, IEnumerable e IEnumerable são implementados.

Por que essa diferença? Se uma multidimensional array é IEnumerable , certamente também deve implementar a versão genérica? Eu notei isso porque tentei usar um método de extensão em um array multidimensional, que falha a menos que você use Cast ou similar; então eu definitivamente posso ver o argumento para fazer matrizes multidimensionais implementar IEnumerable .

Para esclarecer minha dúvida no código, esperaria que o código a seguir fosse impresso quatro vezes, enquanto na verdade ele imprime true , false , true , true :

 int[] singleDimensionArray = new int[10]; int[,] multiDimensional = new int[10, 10]; Debug.WriteLine(singleDimensionArray is IEnumerable); Debug.WriteLine(multiDimensional is IEnumerable); Debug.WriteLine(singleDimensionArray is IEnumerable); Debug.WriteLine(multiDimensional is IEnumerable); 

O CLR tem dois tipos diferentes de matrizes: vetores que são garantidos como unidimensionais com um limite inferior de 0 e matrizes mais gerais que podem ter limites diferentes de zero e um nível diferente de 0.

Da seção 8.9.1 da especificação do CLI:

Além disso, um vetor criado com o tipo de elemento T, implementa a interface System.Collections.Generic.IList (§8.7), onde U: = T.

Eu tenho que dizer que parece muito estranho para mim. Dado que ele já implementa IEnumerable eu não vejo porque ele não deve implementar IEnumerable . Não faria muito sentido implementar o IList , mas a interface genérica simples estaria bem.

Se você quiser isso, você pode chamar Cast (se você estiver usando o .NET 3.5) ou escrever seu próprio método para percorrer a matriz. Para evitar a transmissão, você teria que escrever seu próprio método, que encontrou os limites inferior / superior de cada dimensão, e buscou as coisas dessa maneira. Não muito agradável.

Existe uma solução: você pode converter qualquer array multidimensional para um IEnumerable

 public static class ArrayExtensions { public static IEnumerable ToEnumerable(this Array target) { foreach (var item in target) yield return (T)item; } } 

Matrizes multidimensionais não são matrizes para o propósito da hierarquia de inheritance. Eles são um tipo completamente separado. Além disso, esse tipo não tem um bom suporte da estrutura por dois possíveis motivos:

  • Não é tão útil assim. O único uso real para matrizes multidimensionais é matrizes. Para quase qualquer outra coisa, outras estruturas de dados (por exemplo, matrizes recortadas) são mais adequadas.
  • Não é trivial inventar methods genéricos e úteis para essas estruturas.

No caso de IEnumerable , como isso deve ter sido implementado, ou seja, em que ordem os elementos devem ser enumerados? Não há ordem inerente aos arrays multidimensionais.

Matrizes unidimensionais de limite zero implementam IEnumerable e IEnumerable , mas matrizes multidimensionais, infelizmente, implementa apenas IEnumerable . A “solução alternativa” de @Jader Dias de fato converte uma multidimensional array para IEnumerable mas com um custo enorme: cada elemento de uma matriz será encaixotado.

Aqui está uma versão que não causará boxe para todos os elementos:

 public static class ArrayExtensions { public static IEnumerable ToEnumerable(this T[,] target) { foreach (var item in target) yield return item; } } 

Matrizes irregulares também não suportam IEnumerable , porque estruturas multidimensionais não são realmente uma matriz de um tipo, elas são uma matriz de uma matriz de um tipo:

 int[] singleDimensionArray = new int[10]; int[][] multiJagged = new int[10][]; Debug.WriteLine(singleDimensionArray is IEnumerable); Debug.WriteLine(multiJagged is IEnumerable); Debug.WriteLine(singleDimensionArray is IEnumerable); Debug.WriteLine(multiJagged is IEnumerable); 

Imprime verdadeiro, verdadeiro, verdadeiro e verdadeiro.

Nota : int[,] não é um IEnumerable , que é pelas razões especificadas na outra resposta, ou seja, não há nenhuma maneira genérica de saber qual dimensão para iterar. Com arrays irregulares, não há muito espaço para interpretação, porque a syntax é bem clara sobre ser uma matriz de arrays.

Pense inversamente. A matriz 2d já existe. Apenas enumere. Crie uma matriz 2D com pontuação e local de uma matriz inicial ou marcas, incluindo valores duplicados.

 int[] secondmarks = {20, 15, 31, 34, 35, 50, 40, 90, 99, 100, 20}; IEnumerable 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(); 

Resultados:

 Score Place 100 1 99 2 90 3 50 4 40 5 35 6 34 7 31 8 20 9 20 10 15 11