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()
です。次の 2 行はそれぞれ、によって出力されたモジュールのセッション状態でスクリプト ブロックを呼び出しますGet-Module
。
& (Get-Module 'ModuleName').NewBoundScriptBlock({[c]::new()})
& (Get-Module 'ModuleName') {[c]::new()}}
後者には、オブジェクトがパイプラインに書き込まれるときに、スクリプト ブロックの途中でパイプラインに制御の流れがもたらされるという利点があります。 .NewBoundScriptBlock()
一方、パイプラインに書き込まれたすべてのオブジェクトを収集し、スクリプト ブロック全体の実行が完了すると生成されます。