# array
C:\> (1,2,3).count
3
C:\> (1,2,3 | measure).count
3
# hashtable
C:\> @{1=1; 2=2; 3=3}.count
3
C:\> (@{1=1; 2=2; 3=3} | measure).count
1
# array returned from function
C:\> function UnrollMe { $args }
C:\> (UnrollMe a,b,c).count
3
C:\> (UnrollMe a,b,c | measure).count
1
C:\> (1,2,3).gettype() -eq (UnrollMe a,b,c).gettype()
True
与 HashTables 的差异是众所周知的,尽管官方文档只是间接提及(通过示例)。
不过,函数的问题对我来说是新闻。我有点震惊它以前没有咬过我。我们脚本编写者可以遵循一些指导原则吗?我知道在 C# 中编写 cmdlet 时,WriteObject 有一个重载,您可以在其中显式控制枚举,但是 AFAIK 在 Posh 语言本身中没有这样的构造。正如最后一个示例所示,Posh 解释器似乎相信管道对象的类型没有区别。我怀疑引擎盖下可能存在一些 Object 与 PSObject 的怪异之处,但是当您编写纯 Posh 并期望脚本语言“正常工作”时,这几乎没有用。
/ 编辑 /
基思正确地指出,在我的示例中,我传入了一个 string[] 参数而不是 3 个字符串参数。换句话说,Measure-Object 说 Count=1 的原因是因为它看到了一个数组的数组,其第一个元素是 @("a", "b", "c")。很公平。这些知识使您可以通过多种方式解决该问题:
# stick to single objects
C:\> (UnrollMe a b c | measure).count
3
# rewrite the function to handle nesting
C:\> function UnrollMe2 { $args[0] }
C:\> (UnrollMe2 a,b,c | measure).count
3
# ditto
C:\> function UnrollMe3 { $args | %{ $_ } }
C:\> (UnrollMe3 a,b,c | measure).count
3
然而,这并不能解释一切……
# as seen earlier - if we're truly returning @( @("a","b","c") ) why not count=1?
C:\> (UnrollMe a,b,c).count
3
# our theory must also explain these results:
C:\> ((UnrollMe a,b,c) | measure).count
3
C:\> ( @(@("a","b","c")) | measure).count
3
C:\> ((UnrollMe a,b,c d) | measure).count
2
据我推测,还有另一条规则在起作用:如果你有一个只有一个元素的数组并且解析器处于表达式模式,那么解释器将“解包”所述元素。我还缺少更多的微妙之处吗?