PowerShell 5.1 两个相似函数返回类型不一致的原因
问题背景
在PowerShell 5.1环境中,两个逻辑高度相似的自定义函数出现了返回类型不一致的异常:
DoWork1:先将指定-OutputAs DataTables参数的Invoke-Sqlcmd查询结果赋值给变量,再通过return返回,最终返回DataRow类型DoWork2:直接return Invoke-Sqlcmd的执行结果,最终返回DataTable类型
复现代码
function Main { $result1 = DoWork1 $result1.GetType() $result2 = DoWork2 $result2.GetType() } function DoWork1 { $result1 = Invoke-Sqlcmd -Query "select top 1 * from customer" -ServerInstance "(localdb)\MSSQLLocalDB" -Database "Database1" -OutputAs DataTables # 赋值给变量后返回 return $result1 } function DoWork2 { # 不赋值直接返回结果 return Invoke-Sqlcmd -Query "select top 1 * from customer" -ServerInstance "(localdb)\MSSQLLocalDB" -Database "Database1" -OutputAs DataTables } Main
实际运行输出
IsPublic IsSerial Name BaseType -------- -------- ---- -------- True False DataRow System.Object True True DataTable System.ComponentModel.MarshalByValueComponent
根本原因
类型差异是PowerShell 5.1的两个默认行为共同作用的结果:
- 默认自动枚举(Unrolling)机制
PowerShell会对所有实现了IEnumerable接口的非特殊类型(排除字符串、哈希表等预设例外类型)执行单级展开:不会直接返回集合对象本身,而是遍历集合将内部元素逐个输出。DataTable属于会被自动枚举的类型,枚举后产出的元素是其内部存储的DataRow对象。 - 两种写法的枚举触发时机不同
DoWork2的写法中,Invoke-Sqlcmd的执行结果直接通过return写入函数输出流,整条命令的原始输出不会被提前枚举,因此原始DataTable对象被完整返回。DoWork1的写法中,Invoke-Sqlcmd的结果先执行变量赋值操作,赋值过程会触发PowerShell的自动枚举:原始返回的DataTable被展开为内部的DataRow集合。由于示例查询只返回1行数据,赋值后变量中存储的就是单个DataRow对象,最终返回值自然是DataRow类型。
如果需要两种写法都稳定返回原始DataTable对象,可以通过两种方式阻止自动枚举:
- 返回变量时使用一元数组运算符包装:
return ,$result1 - 使用
Write-Output指定不枚举参数:Write-Output $result1 -NoEnumerate
内容的提问来源于stack exchange,提问作者Rod
相关产品推荐
相关产品推荐

