Question

Je viens de remarquer qu'un tableau multidimensionnel en C # n'implémente pas IEnumerable < T > , alors qu'il implémente IEnumerable . Pour les tableaux à une dimension, IEnumerable < T > et IEnumerable sont implémentés.

Pourquoi cette différence? Si un tableau multidimensionnel est IEnumerable , la version générique devrait-elle également être implémentée? J'ai remarqué cela parce que j'ai essayé d'utiliser une méthode d'extension sur un tableau multidimensionnel, qui échoue à moins d'utiliser Cast ou similaire; je peux donc clairement voir un argument en faveur de la mise en œuvre de tableaux multidimensionnels IEnumerable < T > .

Pour clarifier ma question dans le code, je m'attendrais à ce que le code suivant imprime true quatre fois, alors qu'il imprime réellement 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);
Était-ce utile?

La solution

Le CLR a deux types de tableaux différents: les vecteurs garantis unidimensionnels avec une limite inférieure de 0 et les tableaux plus généraux pouvant avoir des limites non nulles et un rang autre que 0.

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

  

De plus, un vecteur créé avec   type d'élément T, implémente le   interface    System.Collections.Generic.IList < U >   (& # 167; 8.7), où U: = T.

Je dois dire que cela me semble assez étrange. Etant donné qu'il implémente déjà IEnumerable , je ne vois pas pourquoi il ne devrait pas implémenter IEnumerable < T > . Cela n'aurait pas beaucoup de sens d'implémenter IList < T > , mais l'interface générique simple irait bien.

Si vous le souhaitez, vous pouvez appeler Cast < T > (si vous utilisez .NET 3.5) ou écrire votre propre méthode pour parcourir le tableau. Pour éviter le casting, vous devez écrire votre propre méthode qui trouve les limites inférieure / supérieure de chaque dimension et récupère les éléments de cette façon. Pas terriblement agréable.

Autres conseils

Il existe une solution de contournement: vous pouvez convertir n’importe quel tableau multidimensionnel en un IEnumerable

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

Les tableaux multidimensionnels ne sont pas aux fins de la hiérarchie d'héritage. Ils sont un type complètement séparé. De plus, ce type n’est pas bien supporté par le framework pour deux raisons possibles:

  • Ce n'est pas vraiment utile. Les matrices sont la seule utilisation réelle des tableaux multidimensionnels. Pour presque tout le reste, d’autres structures de données (par exemple, des tableaux déchiquetés) sont mieux adaptées.
  • Il n’est pas facile de concevoir des méthodes génériques et utiles pour ces structures.

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

Les tableaux à une dimension liés à zéro implémentent à la fois IEnumerable et IEnumerable < T > , mais les tableaux multidimensionnels, malheureusement, implémentent uniquement IEnumerable . La "solution de contournement" by @Jader Dias convertit en effet un tableau multidimensionnel en IEnumerable < T > mais avec un coût énorme: chaque élément d’un tableau sera encadré.

Voici une version qui ne causera pas la 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;
    }
}

Les tableaux déchiquetés ne prennent pas en charge IEnumerable < int > , car les structures multidimensionnelles ne sont pas vraiment un tableau de type, mais un tableau de tableau de 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 true, true, true, true.

Remarque : int [,] n'est pas un IEnumerable < int [] > , c'est pour les raisons spécifiées dans l'autre réponse, à savoir il n'y a pas de moyen générique de savoir quelle dimension à itérer. Avec les tableaux en dents de scie, il n'y a pas autant de place pour l'interprétation car la syntaxe est assez claire: il s'agit d'un tableau de tableaux.

Pensez à l'inverse. Le tableau 2D existe déjà. Il suffit de l'énumérer. Créez un tableau 2D avec le score et l'emplacement d'un tableau ou de marques initiales, y compris les valeurs en double.

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 
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top