PSA:有一个已知问题是在内存中保留类的旧副本。如果你不知道的话,它会让使用类变得非常混乱。你可以在这里阅读。
using
容易陷入陷阱
该using
关键字容易出现以下各种陷阱:
- 除非您在语句中指定模块的完整路径,否则该
using
语句不适用于不在的模块。这是相当令人惊讶的,因为尽管通过语句可用的模块可能无法工作,具体取决于模块的加载方式。PSModulePath
using
Get-Module
using
- 该
using
语句只能在“脚本”的开头使用。没有任何组合[scriptblock]::Create()
或New-Module
似乎可以克服这一点。传递给的字符串Invoke-Expression
似乎充当了一种独立的脚本;using
在这种字符串类型的工作开头的语句。也就是说,Invoke-Expression "using module $path"
可以成功,但模块内容可用的范围似乎相当难以理解。例如,如果Invoke-Expression "using module $path"
在 Pester 脚本块中使用 ,则模块内的类在同一个 Pester 脚本块中不可用。
以上陈述是基于这组测试。
ScriptsToProcess
防止访问私有模块功能
在模块清单引用的脚本中定义一个类,ScriptsToProcess
乍一看似乎是从模块中导出类。但是,它不是导出类,而是“在全局 SessionState 而不是模块中创建类,因此它......无法访问私有函数”。据我所知,使用ScriptsToProcess
就像以以下方式在模块外部定义类:
# this is like defining c in class.ps1 and referring to it in ScriptsToProcess
class c {
[string] priv () { return priv }
[string] pub () { return pub }
}
# this is like defining priv and pub in module.psm1 and referring to it in RootModule
New-Module {
function priv { 'private function' }
function pub { 'public function' }
Export-ModuleMember 'pub'
} | Import-Module
[c]::new().pub() # succeeds
[c]::new().priv() # fails
调用这会导致
public function
priv : The term 'priv' is not recognized ...
+ [string] priv () { return priv } ...
priv
即使priv
从导入该模块时定义的类调用模块函数,该类也无法访问该模块函数。这可能是您想要的,但我还没有找到它的用途,因为我发现类方法通常需要访问模块中我想保持私有的某些函数。
.NewBoundScriptBlock()
似乎工作可靠
调用绑定到包含该类的模块的脚本块似乎可以可靠地导出类的实例,并且不会受到陷阱的影响using
。考虑这个包含一个类并已导入的模块:
New-Module 'ModuleName' { class c {$p = 'some value'} } |
Import-Module
[c]::new()
在绑定到模块的脚本块内调用会生成一个类型为 的对象[c]
:
PS C:\> $c = & (Get-Module 'ModuleName').NewBoundScriptBlock({[c]::new()})
PS C:\> $c.p
some value
惯用的替代方法.NewBoundScriptBlock()
似乎有一个更短的、惯用的替代.NewBoundScriptBlock()
. 以下两行分别调用模块输出的会话状态中的脚本块Get-Module
:
& (Get-Module 'ModuleName').NewBoundScriptBlock({[c]::new()})
& (Get-Module 'ModuleName') {[c]::new()}}
后者的优点是当对象被写入管道时,它将向管道中间脚本块产生控制流。 .NewBoundScriptBlock()
另一方面,收集写入管道的所有对象,并且仅在整个脚本块的执行完成后才产生。