web-dev-qa-db-fra.com

Pourquoi les érayes multidimensionnelles C # ne sont-elles pas implémenter iEnumerable <T>?

Je viens de remarquer qu'un tableau multidimensionnel en C # ne met pas en œuvre IEnumerable<T>, alors qu'il applique IEnumerable. Pour les tableaux monocensionnels, les deux IEnumerable<T> et IEnumerable sont mis en œuvre.

Pourquoi cette différence? Si une matrice multidimensionnelle est IEnumerable, il devrait également également mettre en œuvre la version générique? J'ai remarqué cela parce que j'ai essayé d'utiliser une méthode d'extension sur une matrice multidimensionnelle, qui échoue à moins que vous n'utilisiez Cast<T> ou similaire; Donc, je peux certainement voir un argument de fabrication de matrices multidimensionnelles implémenter IEnumerable<T>.

Pour clarifier ma question dans le code, je m'attendrais à imprimer le code suivant true quatre fois, alors qu'il imprime en fait true, false, true, true:

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);
64
driis

Le CLR a deux types différents de matrices: vecteurs qui sont garantis à un dimensionnement avec une limite inférieure de 0 et plus de réseaux généraux pouvant avoir des limites non nuls et un rang autre que 0.

À partir de la section 8.9.1 de la spécification CLI:

De plus, un vecteur créé avec l'élément type T, implémente l'interface System.Collections.Generic.IList<U> (§8.7), où u: = T.

Je dois dire que ça me semble assez étrange. Étant donné qu'il implémente déjà IEnumerable je ne vois pas pourquoi il ne devrait pas mettre en œuvre IEnumerable<T>. Cela ne ferait pas autant de sens à mettre en œuvre IList<T>, mais la simple interface générique irait bien.

Si vous le souhaitez, vous pourriez appeler Cast<T> (si vous utilisez .NET 3.5) ou écrivez votre propre méthode à itérer via le tableau. Pour éviter de casting, vous devez écrire votre propre méthode qui a trouvé les limites inférieure/supérieure de chaque dimension et extraites des objets de cette façon. Pas terriblement agréable.

46
Jon Skeet

Il y a une solution de contournement: vous pouvez convertir n'importe quel tableau multidimensionnel en un iNeumable

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

Les matrices multidimensionnelles sont non tableaux aux fins de la hiérarchie de l'héritage. Ils sont un type complètement séparé. De plus, ce type n'a pas de bon soutien du cadre pour deux raisons possibles:

  • Ce n'est pas vraiment utile. Le seul usage réel pour les matrices multidimensionnelles est la matrice. Pour presque toute autre chose, d'autres structures de données (par exemple, les tableaux déchiquetés) conviennent mieux.
  • Il n'est pas trivial de concevoir des méthodes génériques et utiles pour ces structures.

Dans le cas de IEnumerable, comment cela devrait-il avoir été mis en œuvre, c'est-à-dire dans quel ordre les éléments devraient-ils être énumérées? Il n'y a pas d'ordre inhérent aux tableaux multidimensionnels.

4
Konrad Rudolph

Les tableaux de dimension unique nuls implémentent les deux IEnumerable et IEnumerable<T>, mais les tableaux multidimensionnels, malheureusement, implémentent uniquement IEnumerable. La "solution de contournement" de @jader diaas convertit en effet un tableau multidimensionnel en IEnumerable<T> Mais avec un coût énorme: chaque élément d'un tableau sera en boîte.

Voici une version qui ne provoquera pas de boxe pour chaque élément:

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

Les matrices déchiquetées ne soutiennent pas IEnumerable<int> Soit, car des structures multidimensionnelles ne sont pas vraiment un tableau d'un type, ils sont un tableau d'un tableau d'un type:

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);

Imprime vrai, vrai, vrai, vrai.

NOTE: int[,] n'est pas un IEnumerable<int[]>, c'est pour les raisons spécifiées dans l'autre réponse, à savoir qu'il n'y a pas de moyen générique de savoir quelle dimension à parcourir. Avec des matrices déchiquetées, il n'y a pas autant de place à interprétation car la syntaxe est assez claire à ce sujet étant une gamme de tableaux.

0
Matthew Scharley

Penser inversement. Le tableau 2D existe déjà. Juste l'énumérer. Créez un tableau 2D avec le score et le lieu d'un tableau initial ou des marques, y compris des valeurs dupliquées.

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();

Résultats:

Score Place

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