谁见过这个潜在的 powershell 对象 属性 被视为方法调用陷阱?
Who has seen this potential powershell object property treated as method call booby trap?
以下不是实际问题,而是关于一些意外的 PowerShell 语法的警示故事。唯一真正的问题是“这种行为是为许多人所熟知还是仅为少数 PowerShell 开发人员所熟知(即那些工作 ON PowerShell 而不仅仅是 WITH PowerShell )?”注意:例子只是为了演示效果,不代表有意义的代码(不用问目的是什么)。
在使用 PowerShell (5.1.18362.145) switch
语句时,我收到以下错误,
PS > $xx = gi somefile
PS > switch ($xx.directory) {
>> $xx.directory{6}
>> }
At line:2 char:17
+ $xx.directory{6}
+ ~
Missing statement block in switch statement clause.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : MissingSwitchStatementClause
鉴于 switch
上的 previous research,我希望 $xx.directory
表达式都被计算并转换为(匹配的)字符串。显然 {6}
应该是语句子句。也许发生了一些奇怪的解析。尝试将表达式与语句分开,
PS > switch ($xx.directory) {
$xx.directory {6}
}
6
PS >
好的,如果我们都尝试一下会发生什么,
PS > switch ($xx.directory) {
>> $xx.directory{5} {6}
>> }
Method invocation failed because [System.IO.FileInfo] does not contain a method named 'directory'.
At line:2 char:1
+ $xx.directory{5} {6}
+ ~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
什么???我知道大括号 kinda 看起来像圆括号,但这里发生了什么?让我们用实际的方法来尝试一下,
PS > 'fred'.substring{1}
Cannot find an overload for "substring" and the argument count: "1".
At line:1 char:1
+ 'fred'.substring{1}
+ ~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest
但是 String.Substring
确实有一个参数的重载,尽管它应该是一个 int
。这是要传递什么? (提示:它长什么样子?)让我们来看看,
PS > Add-Type @'
>> public class huh {
>> public void passing(object o)
>> {
>> System.Console.WriteLine(o.GetType().ToString());
>> }
>> }
>> '@
PS > $whatsit=New-Object huh
PS > $whatsit.passing{1}
System.Management.Automation.ScriptBlock
PS >
谁打的?
关于唯一的其他问题是,“有人知道文档中描述的位置吗(假设它仍在 7.2+ 中发生)?” (说真的,我想知道是不是。)
作为 - 也许不幸 - 语法糖,PowerShell 允许您缩短:
$object.Method({ ... })
至:
$object.Method{ ... }
注:
在两种情况下方法名后不能有space(而 C# 允许 "foo".Substring (1)
,例如)。
上例中的 Method
仅需 作为方法名称在语法上有效 才能将两个表达式视为方法调用- 尝试调用方法,即使不存在这样的方法或名称恰好引用 属性。
换句话说:
- 接受完全一个(非可选)参数类型script block的方法(
[scriptblock]
; { ... }
) 允许不带括号的调用 ((...)
).
可以说,如此狭窄的用例不需要语法糖:
限制对脚本块的支持将语法糖限制为PowerShell-provided/-targeted类型及其方法,假设脚本块是特定于 PowerShell 的功能。
不是用space分隔名称和开头{
的要求与脚本块的方式不一致通常传递给 cmdlets(例如 1, 2, 3 | ForEach-Object { $_ + 1 }
与 (1, 2, 3).ForEach{ $_ + 1 }
- 见下文)
一旦必须传递 两个或更多 参数就必须切换回 (...)
很尴尬。
据推测,这是为了减少一种常见情况的“语法噪音”:使用 PSv4+ .ForEach()
和 .Where()
array methods, introduced for the DSC (Desired State Configuration) 功能,通常 仅通过脚本块调用;例如:
(1, 2, 3).ForEach({ $_ + 1 })
可以简化为(1, 2, 3).ForEach{ $_ + 1 }
关于文档:
- 行为是 described only in the context of the aforementioned
.ForEach()
and .Where()
methods in the context of the conceptual about_Arrays 帮助主题:
The syntax requires the usage of a script block. Parentheses are optional if the scriptblock is the only parameter. Also, there must not be a space between the method and the opening parenthesis or brace.
- 鉴于它适用于具有适当签名的任何方法(无论.NET类型如何,无论它是实例还是静态方法),它应该可以说是(也)记录在概念性 about_Methods 帮助主题中,但在撰写本文时并非如此。
即使在 about_Methods
中有覆盖,但挑战是甚至 推断 正在尝试 方法调用 当您不希望出现这种情况时 - 至少在 switch
情况下错误消息没有帮助。
设计思路:
请注意,.ForEach()
和 .Where()
方法通常不太合适,因为大多数本机 PowerShell 功能不依赖于 方法 ,并且即使是常规的方法调用语法也会导致与用于调用所有其他命令(cmdlet、函数、脚本、外部程序)的类似 shell 的语法混淆 - 例如,$foo.Get('foo', bar'
) 与 Get-Foo foo bar
.
This rejected RFC on GitHub 提议引入 -foreach
和 -where
运算符 ,这将允许以下更符合 PowerShell 惯用的语法:
1, 2, 3 -foreach { $_ + 1 }
1, 2, 3, 2 -where { $_ -eq 2 }, 'First'
以下不是实际问题,而是关于一些意外的 PowerShell 语法的警示故事。唯一真正的问题是“这种行为是为许多人所熟知还是仅为少数 PowerShell 开发人员所熟知(即那些工作 ON PowerShell 而不仅仅是 WITH PowerShell )?”注意:例子只是为了演示效果,不代表有意义的代码(不用问目的是什么)。
在使用 PowerShell (5.1.18362.145) switch
语句时,我收到以下错误,
PS > $xx = gi somefile
PS > switch ($xx.directory) {
>> $xx.directory{6}
>> }
At line:2 char:17
+ $xx.directory{6}
+ ~
Missing statement block in switch statement clause.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : MissingSwitchStatementClause
鉴于 switch
上的 previous research,我希望 $xx.directory
表达式都被计算并转换为(匹配的)字符串。显然 {6}
应该是语句子句。也许发生了一些奇怪的解析。尝试将表达式与语句分开,
PS > switch ($xx.directory) {
$xx.directory {6}
}
6
PS >
好的,如果我们都尝试一下会发生什么,
PS > switch ($xx.directory) {
>> $xx.directory{5} {6}
>> }
Method invocation failed because [System.IO.FileInfo] does not contain a method named 'directory'.
At line:2 char:1
+ $xx.directory{5} {6}
+ ~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
什么???我知道大括号 kinda 看起来像圆括号,但这里发生了什么?让我们用实际的方法来尝试一下,
PS > 'fred'.substring{1}
Cannot find an overload for "substring" and the argument count: "1".
At line:1 char:1
+ 'fred'.substring{1}
+ ~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest
但是 String.Substring
确实有一个参数的重载,尽管它应该是一个 int
。这是要传递什么? (提示:它长什么样子?)让我们来看看,
PS > Add-Type @'
>> public class huh {
>> public void passing(object o)
>> {
>> System.Console.WriteLine(o.GetType().ToString());
>> }
>> }
>> '@
PS > $whatsit=New-Object huh
PS > $whatsit.passing{1}
System.Management.Automation.ScriptBlock
PS >
谁打的?
关于唯一的其他问题是,“有人知道文档中描述的位置吗(假设它仍在 7.2+ 中发生)?” (说真的,我想知道是不是。)
作为 - 也许不幸 - 语法糖,PowerShell 允许您缩短:
$object.Method({ ... })
至:
$object.Method{ ... }
注:
在两种情况下方法名后不能有space(而 C# 允许
"foo".Substring (1)
,例如)。
上例中的 Method
仅需 作为方法名称在语法上有效 才能将两个表达式视为方法调用- 尝试调用方法,即使不存在这样的方法或名称恰好引用 属性。
换句话说:
- 接受完全一个(非可选)参数类型script block的方法(
[scriptblock]
;{ ... }
) 允许不带括号的调用 ((...)
).
可以说,如此狭窄的用例不需要语法糖:
限制对脚本块的支持将语法糖限制为PowerShell-provided/-targeted类型及其方法,假设脚本块是特定于 PowerShell 的功能。
不是用space分隔名称和开头
{
的要求与脚本块的方式不一致通常传递给 cmdlets(例如1, 2, 3 | ForEach-Object { $_ + 1 }
与(1, 2, 3).ForEach{ $_ + 1 }
- 见下文)一旦必须传递 两个或更多 参数就必须切换回
(...)
很尴尬。
据推测,这是为了减少一种常见情况的“语法噪音”:使用 PSv4+ .ForEach()
和 .Where()
array methods, introduced for the DSC (Desired State Configuration) 功能,通常 仅通过脚本块调用;例如:
(1, 2, 3).ForEach({ $_ + 1 })
可以简化为(1, 2, 3).ForEach{ $_ + 1 }
关于文档:
- 行为是 described only in the context of the aforementioned
.ForEach()
and.Where()
methods in the context of the conceptual about_Arrays 帮助主题:
The syntax requires the usage of a script block. Parentheses are optional if the scriptblock is the only parameter. Also, there must not be a space between the method and the opening parenthesis or brace.
- 鉴于它适用于具有适当签名的任何方法(无论.NET类型如何,无论它是实例还是静态方法),它应该可以说是(也)记录在概念性 about_Methods 帮助主题中,但在撰写本文时并非如此。
即使在 about_Methods
中有覆盖,但挑战是甚至 推断 正在尝试 方法调用 当您不希望出现这种情况时 - 至少在 switch
情况下错误消息没有帮助。
设计思路:
请注意,.ForEach()
和 .Where()
方法通常不太合适,因为大多数本机 PowerShell 功能不依赖于 方法 ,并且即使是常规的方法调用语法也会导致与用于调用所有其他命令(cmdlet、函数、脚本、外部程序)的类似 shell 的语法混淆 - 例如,$foo.Get('foo', bar'
) 与 Get-Foo foo bar
.
This rejected RFC on GitHub 提议引入 -foreach
和 -where
运算符 ,这将允许以下更符合 PowerShell 惯用的语法:
1, 2, 3 -foreach { $_ + 1 }
1, 2, 3, 2 -where { $_ -eq 2 }, 'First'