11

我有以下 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”类型。

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

编辑:

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

4

4 回答 4

20

我不知道人们提出的其他问题,但我可以想到两个可能的原因,为什么你会返回一个Object[].

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

    | Out-Null
    

    例如,

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

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

  2. 另一种可能性是 PowerShell 将返回的各种集合转换为Object[]s。使用,运算符返回未损坏的值:

    return , $dt
    

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

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

    昨天我自己也碰到了这个。我一生都无法弄清楚为什么有人会认为默默地转换Object[]为有用。

于 2012-12-22T00:19:23.790 回答
0

您发布的内容确实存在一些问题。由于您使用 显式创建了一个 DataTable 对象New-Object System.Data.DataTable,因此没有理由也将其强制转换为具有 的 DataTable 类型[System.Data.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

它工作得很好。我怀疑导致您的问题的位可能是您为简洁而排除的位。快捷方式很少,而且您很少从部分数据中获得准确的答案。

于 2012-12-20T15:10:18.110 回答
0

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

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

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

您还需要注意返回值的方法(.Add() 方法为此而臭名昭著),您不会通过分配给变量或通过管道传递到空值来使用这些方法。

于 2012-12-20T20:27:51.780 回答
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 的博客:powershell 函数如何返回工作

于 2014-02-19T04:46:14.160 回答