Domanda

Ho appena notato che un array multidimensionale in C # non implementa IEnumerable < T > , mentre implementa IEnumerable . Per gli array monodimensionali, sono implementati sia IEnumerable < T > che IEnumerable .

Perché questa differenza? Se un array multidimensionale è IEnumerable , sicuramente dovrebbe implementare anche la versione generica? Ho notato questo perché ho cercato di utilizzare un metodo di estensione su un array multidimensionale, che non riesce a meno che non si usi Cast < T > o simile; quindi posso sicuramente vedere l'argomento per rendere le matrici multidimensionali implementano IEnumerable < T > .

Per chiarire la mia domanda nel codice, mi aspetto che il seguente codice stampi true quattro volte, mentre in realtà stampa 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);
È stato utile?

Soluzione

Il CLR ha due diversi tipi di array: vettori che sono garantiti come monodimensionali con un limite inferiore di 0 e array più generali che possono avere limiti diversi da zero e un rango altro di 0.

Dalla sezione 8.9.1 delle specifiche CLI:

  

Inoltre, un vettore creato con   elemento tipo T, implementa il   interfaccia    System.Collections.Generic.IList < U >   (§8.7), dove U: = T.

Devo dire che mi sembra abbastanza strano. Dato che implementa già IEnumerable non vedo perché non dovrebbe implementare IEnumerable < T > . Non avrebbe lo stesso senso implementare IList < T > , ma la semplice interfaccia generica andrebbe bene.

Se vuoi questo, puoi chiamare Cast < T > (se stai usando .NET 3.5) o scrivere il tuo metodo per iterare attraverso l'array. Per evitare il casting dovresti scrivere il tuo metodo che ha trovato i limiti inferiore / superiore di ogni dimensione e ha recuperato le cose in quel modo. Non terribilmente piacevole.

Altri suggerimenti

Esiste una soluzione alternativa: è possibile convertire qualsiasi array multidimensionale in un IEnumerable

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

Gli array multidimensionali sono non array ai fini della gerarchia dell'ereditarietà. Sono un tipo completamente separato. Inoltre, questo tipo non ha un buon supporto dal framework per due possibili motivi:

  • Non è poi così utile. L'unico vero utilizzo per le matrici multidimensionali sono le matrici. Per quasi tutto il resto, altre strutture di dati (ad esempio array frastagliati) sono più adatte.
  • Non è banale escogitare metodi generici e utili per queste strutture.

Nel caso di IEnumerable , come dovrebbe essere implementato, ovvero in quale ordine devono essere elencati gli elementi? Non esiste un ordine inerente alle matrici multidimensionali.

Le matrici monodimensionali con limite zero implementano sia IEnumerable che IEnumerable < T > , ma purtroppo le matrici multidimensionali implementano solo IEnumerable . La "soluzione alternativa" di @Jader Dias converte in effetti un array multidimensionale in IEnumerable < T > ma con un costo enorme: ogni elemento di un array verrà inscatolato.

Ecco una versione che non causerà la boxe per ogni elemento:

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

Le matrici frastagliate non supportano IEnumerable < int > , poiché le strutture multidimensionali non sono realmente una matrice di un tipo, sono una matrice di una matrice di un tipo:

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

Stampa vero, vero, vero, vero.

Nota : int [,] non è un IEnumerable < int [] > , questo è per i motivi specificati nell'altro risposta, vale a dire non esiste un modo generico per sapere su quale dimensione iterare. Con gli array frastagliati, non c'è così tanto spazio per l'interpretazione perché la sintassi è abbastanza chiara sul fatto che si tratta di un array di array.

Pensa inversamente. L'array 2d esiste già. Basta enumerarlo. Crea un array 2d con punteggio e posizione di un array o segni iniziali, inclusi i valori duplicati.

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

Risultati:

Score Place

100     1
99      2 
90      3 
50      4 
40      5 
35      6    
34      7    
31      8    
20      9     
20     10 
15     11 
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top