PSA:存在一个已知问题,即在内存中保留类的旧副本。如果你不知道的话,它会让使用类变得非常混乱。你可以阅读它here。
using 容易陷入陷阱
using 关键字容易出现以下各种陷阱:
-
using 语句不适用于不在PSModulePath 中的模块,除非您在using 语句中指定模块的完整路径。这是相当令人惊讶的,因为虽然模块可以通过 Get-Module 使用,但 using 语句可能无法正常工作,具体取决于模块的加载方式。
-
using 语句只能用在“脚本”的开头。 [scriptblock]::Create() 或 New-Module 的组合似乎无法克服这一点。传递给Invoke-Expression 的字符串似乎充当了一种独立的脚本; using 声明在这种字符串类型的开头。也就是说,Invoke-Expression "using module $path" 可以成功,但模块内容可用的范围似乎相当难以理解。例如,如果在 Pester 脚本块中使用 Invoke-Expression "using module $path",则模块内的类在同一个 Pester 脚本块中不可用。
以上陈述基于this set of tests。
ScriptsToProcess 阻止访问私有模块功能
在模块清单的ScriptsToProcess 引用的脚本中定义一个类,乍一看似乎是从模块中导出类。但是,它不是导出类,而是"creates the class in the global SessionState instead of the module's, so it...can't access private functions"。据我所知,使用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() 收集写入管道的所有对象,并且仅在整个脚本块的执行完成后才产生。