2010-02-05 46 views
22

uscitaPerché i param si comportano così?

nullo

codice

class Program 
{   
    static void Main(String[] args) 
    { 
     String s = null; 
     PrintLength(s); 
     PrintLength(s, s); 
     PrintLength(null); 
     PrintLength(null, null);  
     Console.ReadKey(); 
    } 

    private static void PrintLength(params String[] items) 
    { 
     Console.WriteLine(items == null ? "null" : items.Length.ToString()); 
    }  
} 

risposta

28

Questa è una domanda abbastanza frequente. Per i dettagli, vedere la sezione 7.4.1 e 7.4.3.1 della specifica.

In breve: un metodo con un array params è applicabile sia nella "forma normale" che nella "forma espansa". Cioè, si può dire

PrintLength(new string[] {"hello"}); // normal form 
PrintLength("hello"); // expanded form, translated into normal form by compiler. 

Quando dato una chiamata che è applicabile in entrambe le forme , il compilatore sceglie sempre la forma normale sopra la forma estesa.

Supponiamo di aver scelto il modulo espanso ogni volta che erano applicabili entrambi. Supponiamo di avere

void M(params object[] x) {} 

Come passeresti effettivamente un array nullo a questa cosa se scegliamo sempre la forma espansa? Quello sarebbe impossibile!

Supponiamo che hai detto

M(new object[] { "hello" }); 

e abbiamo sempre scelto la forma estesa. Cosa farebbe questo? Bene, una serie di oggetti è un oggetto, quindi questo sceglierebbe la forma espansa: renderebbe un'altra matrice, avvolgere questa cosa nell'array e passare quella!

La scelta della forma espansa rispetto alla forma normale porta a risultati pazzeschi. Scegliere sempre la forma normale sulla forma espansa è la cosa più sensata da fare.

+0

Buone informazioni! –

+0

Buon post Eric. Potrei aggiungere che w/the first PrintLength (null), stai passando un valore nullo alla funzione, dove come nel caso del secondo esempio PrintLength (s) stai passando un puntatore a una stringa (riferimento) che in realtà non fa riferimento a nulla. Tuttavia, il riferimento esiste ancora nella memoria w/un valore di 0 poiché è un puntatore nullo. – regex

+0

Ero sicuro al 90% che era il caso, ma quel 10% continuava a tormentarmi. – ChaosPandion

4

Il PrintLength(null) sta passando un array null cui come PrintLength(null, null) sta passando un string[] con una lunghezza di due contenenti due nulli string oggetti. Sarebbe come passare new string[] { null, null }

Hmm leggendo quello che ho scritto forse che in realtà non risponde alla tua domanda shrug.

Edit:

Questo è probabilmente il motivo: È possibile inviare un elenco separato da virgole di argomenti del tipo specificato nella dichiarazione dei parametri, o una matrice di argomenti del tipo specificato.

http://msdn.microsoft.com/en-us/library/w5zay9db.aspx

+0

Penso che la domanda sia: perché passare un singolo null non supera l'equivalente della nuova stringa [] {null}? Sembra una sorta di comportamento intenzionalmente codificato, ma a quale fine è un po 'misterioso. – technophile

+0

Re: edit Quindi interpreta il null come se tu avessi passato in string [] s = null; Hm. Caso d'angolo interessante. – technophile

5

funziona come progettato, direi:

PrintLength (s);

si sta passando in una singola stringa, che è nullo - all'interno del vostro metodo, items sarà non essere nullo - è una serie di un elemento - di tipo stringa - di valore null

PrintLength (s, s);

Stessa storia qui - si sta passando in due elementi, in modo items nel tuo metodo sarà un array di stringhe due - entrambi i quali essi stessi sono nulli, ma la matrice non è

PrintLength (null);

Questo ovviamente viene interpretata come un singolo valore NULL e quindi items è nullo. Non stai trasmettendo un array, né un elemento di tipo string: stai solo passando un valore nullo di per sé.

PrintLength (null, null);

Questo è ancora una volta - una serie di due elementi, che sono entrambi nulli - ma la matrice di per sé non è nullo, dato che si sta passando due valori.

E 'un po' sconcertante, forse - ma in realtà: quello che serve per verificare la presenza nel metodo PrintLength non è se il vostro Items nel suo complesso è nullo - ma se i valori effettivi items[0] e così via sono nulli.

Ciò che è un po 'strano forse - o contro-intuitivo in un primo momento - è il fatto che il singolo valore "nullo" esplicito è considerato un "nulla" - piuttosto che un array di un singolo elemento di valore null. Perché è così, e se avrebbe potuto essere implementato in modo diverso - non lo so, abbastanza onestamente.

0

Come detto in risposta uno:

  • 1: un array di stringhe con un elemento in esso - l'elemento è nullo

  • 2: un array di stringhe con due elementi in esso, entrambi gli elementi sono nulli

  • nullo: null viene passato al metodo, non un array

  • 2: una matrice di valori nulli è pas sed nel metodo

Problemi correlati