C#开发PowerShell二进制模块的类型转换问题咨询
现象原因
在PowerShell中创建[pscustomobject]时,如果没显式将属性值转换为特定CLR类型(比如[int]$_),PowerShell会自动把该值包装在PSObject实例里。这是因为PowerShell的类型系统是动态的,默认用PSObject封装对象来提供额外元数据和适配能力。当这个PSCustomObject传给C#编写的PowerShell二进制模块时,未显式转换的属性值就会以PSObject类型呈现,而非预期的原始CLR类型(比如int)。
你用Convert.ChangeType转换失败,是因为PSObject本身没实现IConvertible接口,这个方法无法处理PSObject到int的转换逻辑。
是否仅针对int类型?
不是,这个问题并非只针对int类型,而是普遍存在的。任何在[pscustomobject]哈希表中未显式转换为CLR类型的属性值,都会被PowerShell包装成PSObject。比如字符串、日期等类型,只要没显式指定CLR类型(如[string]"example"),在C#中接收时都会是PSObject类型,内部存储着原始值。
解决方法
有两种常用方式能让C#代码直接获取到int类型的属性值:
方式一:在PowerShell端显式转换属性值
创建[pscustomobject]时,对需要强类型的属性显式执行CLR类型转换,就像你示例里的TypedInt = [int]$_那样:
1..100 | foreach { [pscustomobject]@{ Date = (Get-Date).AddHours($_) Int32 = [int]$_ # 显式转换为int类型 TypedInt = [int]$_ Text = "Iteration $_" } } | Get-ExtractedData
这样处理后,C#模块接收该属性时直接就是int类型,无需额外转换。
方式二:在C#代码中正确处理PSObject
如果无法修改PowerShell端的输入代码,可以在C#中通过PSObject的BaseObject属性获取原始值,或者使用PowerShell SDK提供的LanguagePrimitives.ConvertTo方法(该方法专门适配PowerShell的类型转换规则):
// 方法1:通过BaseObject获取原始值 var intValue = (int)((PSObject)myInt32.Value).BaseObject; // 方法2:使用LanguagePrimitives.ConvertTo(推荐,适配更多场景) using System.Management.Automation; // 需要引用该命名空间 var intValue = LanguagePrimitives.ConvertTo<int>((PSObject)myInt32.Value);
LanguagePrimitives.ConvertTo比Convert.ChangeType更适合PowerShell场景,能处理PowerShell特有的类型包装和转换逻辑。
内容的提问来源于stack exchange,提问作者Axel Andersen

