2014-10-22 1 views
12

Ho fatto un errore di battitura più sfortunato mi costa un po 'di tempo prezioso:Come funziona la proprietà Count in PowerShell?

$errors.Count 

Questo restituisce "0", anche se ci sono errori, perché il nome della variabile deve essere singolare. Questo fa lavoro:

$error.clear()    # To ensure a correct repro 
Copy-Item asdf fdsa   # Will show an error 
$error.Count     # Will output "1" 

Tuttavia, ora voglio sapere perché mi ha dato $errors.Countnulla, e perché mi ha dato "0". Così sono andato a fare qualche test, ed ha ottenuto i seguenti risultati:

$asdf.Count     # Will output "0" 
$nrOfEinsteinsInSpace.Count # Will output "0" 
$a = 0; $a.Count;    # Will output "1" 
$b = 2; $a.Count;    # Will output "1" 
$x = 1,2,3; $x.Count;   # Will output "3" 

e la raccolta ancora più dati per essere in grado di fare una domanda sensata qui ho fatto:

$true.Count     # Will output "1" 
$false.Count     # Will output "1" 

Così abbiamo la seguenti casi:

  1. variabili Array (simili), dove .Count stamperà il numero di elementi.
  2. Variabili inesistenti, dove .Count emetterà "0".
  3. Variabili dichiarate, dove .Count emetterà "1".
  4. Variabili integrate, dove .Count emetterà "1".

I casi 2, 3 e 4 non hanno alcun senso per me (ancora). Che cosa sta succedendo qui? Dove è documentato? Come funziona la proprietà .Count?

risposta

14

A partire da PowerShell V3, le proprietà Count e Length hanno ricevuto un trattamento molto speciale non correlato ai dati di tipo esteso (noto anche come sistema ETS o di tipo esteso).

Se l'istanza ha una proprietà Count/Length, quindi tutto continua a funzionare come in V1/V2, viene restituito il valore dall'istanza.

Se l'istanza non ha una proprietà Count/Length, a partire da V3, invece di quello è un errore, si torna 1. Se l'istanza è $ null, si torna 0. Se hai attivato la modalità rigorosa, riceverai un errore come in V2.

Ammetto che questo è un po 'strano, ma risolve un problema comune quando un cmdlet restituisce 0, 1 o più oggetti.

Spesso, è possibile scorrere questi risultati tramite la pipeline o con un'istruzione foreach. Ad esempio:

dir nosuchfile* | % { $_ } 
foreach ($item in dir nosuchfile*) { $_ } 

Nel caso foreach sopra, V2 sarebbe effettivamente entrare nel ciclo se il comando non restituisce alcun valore. Che è stato cambiato in V3 per adattarsi meglio popoli aspettative, ma che significava anche che:

foreach ($item in $null) { $_ } 

anche non entra mai il ciclo.

L'istruzione for è un altro modo per scorrere i risultati, ad es.

$results = dir nosuchfile* 
for ($i = 0; $i -lt $results.Count; $i++) { $results[$i] } 

In questo esempio, non importa quanti oggetti sono in $ result, il ciclo funziona bene. Si noti che in V1/V2, avreste scritto:

$results = @(dir nosuchfile*) 

Questo assicura $ risultato è un array, ma questa sintassi è brutto e molte persone si dimentica, da qui il cambio di sostenere Conte/Lunghezza in un po ' modo più indulgente.

+0

Wow, una risposta piuttosto diversa rispetto alle altre due da @DavidBrabant e Paul. Apprezzo entrambi gli sforzi, non sono sicuro di essere adeguatamente qualificato per decidere quale risposta accettare. Dovrò verificare il lavoro domani se vedo una differenza simile tra V2 e V3. Grazie per il tuo tempo! – Jeroen

+4

Sono lo sviluppatore del team PowerShell che ha implementato questo, ignorando così i ricordi difettosi, la mia risposta è autorevole come si può ottenere. –

+1

Attenzione che la modalità ** strict ** genera ancora un errore come nota Jason! Quello mi ha fatto grattarmi la testa ... –

3

Ecco come penso che funziona:

Caso 1: in array la .Count proprietà in realtà collega alla proprietà .Length, che mostra il numero di elementi della serie

Caso 2: le variabili non-exitent ottenere automaticamente creato da PowerShell e inizializzato con il valore $null

caso 3/4: Su questo io non sono esattamente sicuro perché succede, ma poiché né String né Int o oggetti booleani hanno una proprietà .Count potevo immaginare che la proprietà è ereditato da un oggetto genitore.

Il comportamento suggerisce che la variabile è trattata come matrice così con 1 Valore assegnato l'uscita sarà 1, senza un valore il risultato sarà 0.

Edit: Per ragioni di completezza ecco il link alla documentazione: Technet, grazie @David Brabant

5

Per completare la risposta di Paolo, questo potrebbe essere correlato a extended type data. Per citare la parte rilevante della documentazione:

tipo di dati esteso definisce le proprietà ei metodi ("Soci") di tipi di oggetti in Windows PowerShell aggiuntivi.È possibile estendere qualsiasi tipo di supportato da Windows PowerShell e utilizzare le proprietà e i metodi aggiunti nello stesso modo in cui si utilizzano le proprietà definite nei tipi di oggetto.

E:

Ci sono tre fonti di dati di tipo estesi in Windows PowerShell sessioni. I file Types.ps1xml nella directory di installazione di Windows PowerShell vengono caricati automaticamente in ogni sessione di Windows PowerShell.

Se si apre il file Types.ps1xml (in $pshome), vedrete questo all'inizio del file:

<Type> 
     <Name>System.Array</Name> 
     <Members> 
      <AliasProperty> 
       <Name>Count</Name> 
       <ReferencedMemberName>Length</ReferencedMemberName> 
      </AliasProperty> 
     </Members> 
    </Type> 

Quindi la mia ipotesi è che, fornendo la ".Count" proprietà , PowerShell presume che questo sia un array.

+0

ha avuto ragione :) grazie per il collegamento alla documentazione! – Paul