为什么Powershell认为我试图返回一个对象[]而不是一个DataTable?

时间:2012-12-20 14:47:25

标签: function powershell return-value

我有以下PS功能:

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
}

为简洁起见,删除了大部分功能。我遇到的问题是当我这样调用函数时:

[System.Data.DataTable] $buildData = GetBuildData

我收到以下错误:

  

无法转换“System.Object []”类型的“System.Object []”值   输入“System.Data.DataTable”。

为什么Powershell认为我很想在$ dt变量是DataTable时返回一个object []数组?

编辑:

我已经仔细检查了,$dt确实包含了数据。例如,Rows.Count的数量是1,这是预期的。

4 个答案:

答案 0 :(得分:15)

我不知道人们提出的其他问题,但我可以想到你回到Object[]的两个可能原因。

  1. 可能是您在函数中的其他位置有未捕获的输出。在您的情况下,Fill会返回int。尝试将此添加到函数调用的末尾:

    | Out-Null
    

    如,

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

    如果任何语句返回一个值并且您没有捕获它,则输出将包含在您的返回值中,并且由于此时您将有多个返回值,PowerShell会将它们全部填充到数组中。 / p>

  2. 另一种可能性是PowerShell将所有类型的返回集合转换为Object[] s。使用,运算符返回未编码的值:

    return , $dt
    

    ,创建一个仅包含后面值的数组。就像我猜的那样,这会导致PowerShell自动展开最外面的数组并保留值,因为实际返回值现在是一个只包含单个值的数组。

    return实际上是可选的,因为未捕获的值包含在返回值中。

    昨天我自己碰到了这个。我不能为我的生活弄清楚为什么有人会认为默默地转换为Object[]是有用的。

答案 1 :(得分:0)

您发布的内容确实存在一些问题。由于您使用New-Object System.Data.DataTable显式创建了一个DataTable对象,因此没有理由使用[System.Data.DataTable]将其强制转换为DataTable类型。调用函数时也是如此。您正在返回一个DataTable对象,因此您将返回该对象。此外,如果您确实要指定变量类型,则类型标识符和变量名称之间不应有空格。无论如何,这些问题不会导致您看到的行为。我运行了这段代码:

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

它运作得很好。我怀疑造成你问题的那个位可能是你为了简洁而被排除在外的位。快捷方式很少,您很少从部分数据中获得准确的答案。

答案 2 :(得分:0)

一个促成因素是你实际上并没有调用open和close方法,而是引用它们。 PowerShell正在输出对这些方法以及数据表的引用(由于连接未打开,我想象的实际上并没有填充)。

您需要在开/关方法中包括括号,如下所示:

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

您还需要注意返回值的方法(.Add()方法因此而臭名昭着),您不会通过分配给变量或管道输出为null来消耗它。

答案 3 :(得分:0)

您必须清空所有未分配给变量的点命令

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
}

关于你的问题为什么? ...阅读Keith Hill的博客:how does return work powershell functions