mirror of
https://github.com/PowerShell/PowerShell
synced 2026-06-08 12:12:50 +00:00
Support creating PS class instance that is not bound to any runspace (#3871)
This commit is contained in:
@@ -70,12 +70,17 @@ namespace System.Management.Automation.Internal
|
||||
/// It's not intended to be a public API, but because we generate type in a different assembly it has to be public.
|
||||
/// Return type should be SessionStateInternal, but it violates accessibility consistency, so we use object.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// By default, PowerShell class instantiation usually happens in the same Runspace where the class is defined. In
|
||||
/// that case, the created instance will be bound to the session state used to define that class in the Runspace.
|
||||
/// However, if the instantiation happens in a different Runspace where the class is not defined, then the created
|
||||
/// instance won't be bound to any session state.
|
||||
/// </remarks>
|
||||
/// <returns>SessionStateInternal</returns>
|
||||
public object GetSessionState()
|
||||
{
|
||||
SessionStateInternal ss = null;
|
||||
bool found = _stateMap.TryGetValue(Runspace.DefaultRunspace, out ss);
|
||||
Diagnostics.Assert(found, "We always should be able to find corresponding SessionState");
|
||||
_stateMap.TryGetValue(Runspace.DefaultRunspace, out ss);
|
||||
return ss;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,4 +43,75 @@ Describe 'Misc Test' -Tags "CI" {
|
||||
[C1]::new().Bar() | should be "1;2;3;"
|
||||
}
|
||||
}
|
||||
|
||||
Context 'Class instantiation' {
|
||||
Class C1 {
|
||||
[string] Foo() {
|
||||
return (Get-TestText)
|
||||
}
|
||||
}
|
||||
|
||||
BeforeAll {
|
||||
$ExpectedTextFromBoundInstance = "Class C1 was defined in this Runspace"
|
||||
$ExpectedTextFromUnboundInstance = "New Runspace without class C1 defined"
|
||||
|
||||
## Define 'Get-TestText' in the current Runspace
|
||||
function Get-TestText { return $ExpectedTextFromBoundInstance }
|
||||
|
||||
$NewRunspaceFunctionDefinitions = @"
|
||||
## Define 'Get-TestText' in the new Runspace
|
||||
function Get-TestText { return '$ExpectedTextFromUnboundInstance' }
|
||||
|
||||
## Define the function to create an instance of the given type using the default constructor
|
||||
function New-UnboundInstance([Type]`$type) { `$type::new() }
|
||||
|
||||
## Define the function to call 'Foo()' on the given C1 instance, and return the result
|
||||
function Run-Foo(`$C1Instance) { `$C1Instance.Foo() }
|
||||
"@
|
||||
## Create a new Runspace and define helper functions in it
|
||||
$powershell = [powershell]::Create()
|
||||
$powershell.AddScript($NewRunspaceFunctionDefinitions).Invoke() > $null
|
||||
$powershell.Commands.Clear()
|
||||
|
||||
function InstantiateInNewRunspace([Type]$type) {
|
||||
try {
|
||||
$result = $powershell.AddCommand("New-UnboundInstance").AddParameter("type", $type).Invoke()
|
||||
$result.Count | Should Be 1 > $null
|
||||
return $result[0]
|
||||
} finally {
|
||||
$powershell.Commands.Clear()
|
||||
}
|
||||
}
|
||||
|
||||
function RunFooInNewRunspace($instance) {
|
||||
try {
|
||||
$result = $powershell.AddCommand("Run-Foo").AddParameter("C1Instance", $instance).Invoke()
|
||||
$result.Count | Should Be 1 > $null
|
||||
return $result[0]
|
||||
} finally {
|
||||
$powershell.Commands.Clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AfterAll {
|
||||
$powershell.Dispose()
|
||||
}
|
||||
|
||||
It "Create instance that is bound to a SessionState" {
|
||||
$instance = [C1]::new()
|
||||
## For a bound class instance, the execution of an instance method is
|
||||
## done in the Runspace/SessionState the instance is bound to.
|
||||
$instance.Foo() | Should Be $ExpectedTextFromBoundInstance
|
||||
RunFooInNewRunspace $instance | Should Be $ExpectedTextFromBoundInstance
|
||||
}
|
||||
|
||||
It "Create instance that is NOT bound to a SessionState" {
|
||||
$instance = InstantiateInNewRunspace ([C1])
|
||||
## For an unbound class instance, the execution of an instance method is done in
|
||||
## the Runspace/SessionState where the call to the instance method is made.
|
||||
$instance.Foo() | Should Be $ExpectedTextFromBoundInstance
|
||||
RunFooInNewRunspace $instance | Should Be $ExpectedTextFromUnboundInstance
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user