2012-12-20 15 views
8

Ho la seguente funzione PS:Perché Powershell pensa che sto cercando di restituire un oggetto [] piuttosto che un DataTable?

function GetBuildData { 
    [System.Data.SqlClient.SqlConnection] $conn = New-Object System.Data.SqlClient.SqlConnection 
    [System.Data.SqlClient.SqlCommand] $cmd = New-Object System.Data.SqlClient.SqlCommand 
    [System.Data.SqlClient.SqlDataAdapter] $adapter = New-Object System.Data.SqlClient.SqlDataAdapter 
    [System.Data.DataTable] $dt = New-Object System.Data.DataTable 

    try { 
     [string] $connStr = "myConnectionString" 

     $conn.ConnectionString = $connStr 
     $cmd.Connection = $conn 
     $cmd.CommandText = "SELECT * FROM TestTable" 

     $conn.Open 

     $adapter.SelectCommand = $cmd 

     $adapter.Fill($dt) 

     $conn.Close 
    } 
    catch [system.exception] 
    { 
     Write-Host $_ 
    } 
    finally { 
     $adapter.Dispose 
     $cmd.Dispose 
     $conn.Dispose 
    } 

    return $dt 
} 

La maggior parte della funzione è stata rimossa per brevità. Il problema che ho è quando chiamo la funzione in questo modo:

[System.Data.DataTable] $buildData = GetBuildData

ottengo il seguente errore:

Cannot convert the "System.Object[]" value of type "System.Object[]" to type "System.Data.DataTable".

Perché Powershell pensare che mi vogliono un [] array oggetto restituito quando è ovvio che la variabile $ dt è un DataTable?

EDIT:

Ho ricontrollato, e $dt contiene dati. Ad esempio, il numero di Rows.Count è 1 che è previsto.

+0

in quale riga si è verificato l'errore? il messaggio di errore dovrebbe fornire il numero di linea e di carattere. Presumo che accada qui: $ adapter.Fill ($ dt) ?? – D3vtr0n

+0

Hai mai provato l'operatore ',' come suggerito nella risposta di jpmc26? Mi sono imbattuto in questo problema, e questa era la soluzione. –

+0

Qualcuna delle risposte ha risolto il tuo problema? Se no, potresti aggiungere qualche informazione in più sul motivo per cui non hanno funzionato? – jpmc26

risposta

13

Non so degli altri problemi che la gente sta sollevando, ma posso pensare a due possibili motivi per cui si sta recuperando un Object[].

  1. Potrebbe essere che hai in uscita non catturate da qualche altra parte nella funzione. Nel tuo caso, Fill restituisce un int. Prova ad aggiungere questo alla fine delle chiamate di funzione:

    | Out-Null 
    

    E.g.,

    $adapter.Fill($dt) | Out-Null 
    

    Se una qualsiasi istruzione restituisce un valore e non si sta catturarlo, l'uscita saranno inclusi nel vostro valore di ritorno, e dal momento che si dispone di più valori di ritorno a quel punto, PowerShell tutti li roba in un array.

  2. L'altra possibilità è che PowerShell converte le raccolte restituite di tutti i tipi in Object[] s. Utilizzare l'operatore , per restituire il valore unmangled:

    return , $dt 
    

    Il , crea una matrice contenente solo il valore che segue. Per quanto posso immaginare, questo fa sì che PowerShell srotoli automaticamente l'array più esterno e lasci il valore da solo, poiché il valore di ritorno effettivo è ora un array che contiene solo un singolo valore.

    Il return è in realtà opzionale, poiché i valori non catturati sono inclusi nel valore restituito.

    Mi sono imbattuto in questo solo ieri. Non posso per la vita di me capire perché qualcuno potrebbe pensare di convertire in silenzio a Object[] è utile.

+2

Questa è la risposta! Ora posso riparare il muro dal danno causato dalla mia testa. Idem su "Non posso per la vita di me capire perché qualcuno possa pensare di convertire silenziosamente in' Object [] 'è utile." Forse Microsoft ha un accordo di contraccolpo con un appaltatore di riparazioni a muro? –

+0

BTW, vedo che questo può essere combinato con ** return **, cioè 'return, $ dt' funziona anche se si desidera restituire ** $ dt ** non convertito e terminare la funzione proprio lì. –

+0

Un'altra nota che vorrei aggiungere è che la conversione avviene anche se non si utilizza la parola chiave ** return **. Se l'ultima espressione valutata è ** $ dt **, la funzione restituisce una matrice di oggetti. –

0

Hai un paio di problemi in ciò che hai pubblicato. Poiché si crea in modo esplicito un oggetto DataTable con New-Object System.Data.DataTable, non c'è motivo di forzarlo nel tipo DataTable con [System.Data.DataTable]. Lo stesso vale per quando si chiama la funzione. Stai restituendo un oggetto DataTable, quindi questo è ciò che tornerai indietro. Inoltre, se si desidera specificare il tipo di variabile, non deve esserci uno spazio tra l'identificativo del tipo e il nome della variabile. Indipendentemente da ciò, questi problemi non causerebbero il comportamento che stai vedendo. Ho eseguito questo codice:

function GetBuildData { 
    $dt = New-Object System.Data.DataTable 
    $column1 = New-Object system.Data.DataColumn 'Col1' 
    $column2 = New-Object system.Data.DataColumn 'Col2' 
    $dt.columns.add($column1) 
    $dt.columns.add($column2) 
    $row = $dt.NewRow() 
    $row.col1 = '1' 
    $row.col2 = '2' 
    $dt.rows.add($row) 

    return $dt 
} 

$buildData = GetBuildData 
$buildData 
Col1                  Col2 
----                  ---- 
1                  2 

E ha funzionato bene. Sospetto che il bit che sta causando il tuo problema sia probabilmente nel bit che hai escluso per brevità. Le scorciatoie sono raramente e raramente si ottengono risposte accurate da dati parziali.

+0

Ho aggiunto l'intera funzione, nel caso in cui fornisca indizi sul motivo per cui non funziona per me. –

+0

Nella funzione, se si ha output del contenuto di $ dt, ci sono dei dati? Se fai $ dt.GetType() nella funzione, cosa pensa $ dt è? – EBGreen

+1

Vorrei anche suggerire di eliminare tutti quegli identificatori di tipo quando si creano variabili. Non sono necessari e potrebbero causare il problema, anche se non penso. – EBGreen

0

Un fattore che contribuisce è che in realtà non si stanno chiamando i metodi di apertura e chiusura, ma si fa riferimento ad essi. PowerShell sta emettendo un riferimento a questi metodi e al datatable (che immagino non sia effettivamente compilato a causa del fatto che la connessione non è aperta).

è necessario includere le parentesi sui metodi di apertura/chiusura come questo:

$conn.Open() 
... 
$conn.Close() 

È inoltre necessario stare attenti metodi che restituiscono valori (.add() i metodi sono noti per questo) in cui si' non consumare né assegnando a una variabile o piping a out-null.

0

Devi solo di annullare tutti i comandi di punti che non sono assegnati alle variabili

function GetBuildData { 
    [System.Data.SqlClient.SqlConnection] $conn = New-Object System.Data.SqlClient.SqlConnection 
    [System.Data.SqlClient.SqlCommand] $cmd = New-Object System.Data.SqlClient.SqlCommand 
    [System.Data.SqlClient.SqlDataAdapter] $adapter = New-Object System.Data.SqlClient.SqlDataAdapter 
    [System.Data.DataTable] $dt = New-Object System.Data.DataTable 

    try { 
     [string] $connStr = "myConnectionString" 

     $conn.ConnectionString = $connStr 
     $cmd.Connection = $conn 
     $cmd.CommandText = "SELECT * FROM TestTable" 

     [void]$conn.Open 

     $adapter.SelectCommand = $cmd 

     $adapter.Fill($dt) 

     [void]$conn.Close 
    } 
    catch [system.exception] 
    { 
     Write-Host $_ 
    } 
    finally { 
     [void]$adapter.Dispose 
     [void]$cmd.Dispose 
     [void]$conn.Dispose 
    } 

    $dt 
} 

Per quanto riguarda la tua domanda Perché? ... Leggi il blog di Keith Hill: how does return work powershell functions

Problemi correlati