2013-02-10 12 views
6

Sto lavorando a un piccolo progetto con alcuni tipi diversi di array (ad esempio double[], float[], int[]. Per scopi di verifica/test/sanità mentale, sto stampando alcuni di questi array sulla console mentre procedo. così ho molteplici funzioni che assomigliano a questi di seguito (semplificata per questo esempio - assumere sono solo trattare con gli array monodimensionali):Perché System.Array non può essere un vincolo di tipo?

void Print(float[] a) // prints an array of floats 
{ 
    for (int i = 0; i < a.Length; i++) 
    { 
     Console.Write(a[i]); 
    } 
} 

void Print(double[] a) // prints an array of doubles 
{ 
    for (int i = 0; i < a.Length; i++) 
    { 
     Console.Write(a[i]); 
    } 
} 

io, nella mia infinita saggezza, pensavo di poter ridurre alcuni dei duplicazione del codice semplicemente creando una versione generica di queste funzioni. Così ho provato questo:

void Print<T>(T t) where T : Array 
{ 
    for (int i = 0; i < t.Length; i++) 
    { 
     Console.Write(t.GetValue(i)); 
    } 
} 

Intellisense non si lamenta, ma il compilatore non riesce con un errore molto interessante:

Constraint cannot be special class 'System.Array'

Ho cercato una spiegazione (simile a Object o classi sigillato, ma non ho trovato molto, oltre ad una menzionare on msdn. Qualcuno mi può spiegare perché questo è il caso? Perché non è possibile specificare un vincolo di tipo System.Array?

ps: Durante la digitazione questo fuori, mi sono reso conto che posso realizzare quello che in origine volevo più facilmente, con una semplice funzione come questa:

void Print(System.Array a) 
{ 
    for (int i = 0; i < a.Length; i++) 
    { 
     Console.Write(a.GetValue(i)); 
    } 
} 

È questo il motivo per cui c'è una regola speciale per le matrici nel compilatore ?

risposta

16

La sintassi appropriata per fare quello che vuoi è questo:

void Print<T>(T[] array) 
{ 
    for (int i = 0; i < array.Length; i++) 
    { 
     Console.Write(array[i]); 
    } 
} 
+1

ha un senso, ma io sono ancora curioso _perché_ non posso avere un tipo di vincolo classe base di 'Array' ... – vlad

+0

Inoltre, per curiosità, è molto diverso da utilizzando un parametro di tipo' Array'? C'è un po 'di boxe in corso se uso 'Array'? – vlad

+1

@vlad Non c'è boxe dato che le matrici sono tipi di riferimento, non tipi di valore, anche se stai inscatolando gli oggetti che ne hai ricavato, diversamente da un array tipizzato. Non è nemmeno la stessa poiché un 'array' potrebbe anche essere un array di dimensioni 2, 3 o N, o un array che non è indicizzato a 0. – Servy

1

Se preso la questione alla lettera, sarebbe inutile avere un Array vincolo. È lo stesso che è inutile avere un vincolo ValueType, poiché in realtà non controlla se si utilizza un tipo di valore come argomento generico, ma se il tipo che si sta passando è assegnabile a ValueType.
Quindi è possibile passare anche a Array come argomento generico ed è OK.

cosa è effettivamente utile è di avere un matrice contraint consentendo qualsiasi tipo che deriva da Array, ma non Array stessa:

void Print<TArr>(TArr t) where TArr : array //or [*] or other fancy syntax 

Dove T può essere [], [,], [,,], [,,,], e così sopra. L'unico parametro non-Array non generico è che conosciamo il tipo di elemento dell'array.

Un altro modo per risolvere questo è quello di creare una classe personalizzata Array<T> con overload dell'operatore implicita di T[], T[,], T[,,] ecc

Edit:
Non c'è modo per raggiungere questo obiettivo anche in CIL (attualmente), perché int[,] e Array non differiscono in alcuna interfaccia o costruttore. Abbiamo bisogno di contrabbando where T : Array but not Array itself.

+0

Non sarebbe del tutto inutile. Se non fosse per la proibizione, si potrebbe scrivere un 'CopyAndReverseArraySegment (T dest, T source, int start, int length) dove T: System.Array' e fargli accettare invocazioni in cui uno o entrambi l'origine o la destinazione era' System.Array', ma rifiuta ancora le chiamate in cui 'source' e' dest' erano tipi di array incompatibili. Così com'è, non credo che ci sia un modo per permettere che 'System.Array' come un particolare tipo per uno dei parametri senza che nessuna derivata di quel tipo sia ritenuta accettabile. – supercat

Problemi correlati