unexpected side-effect of 'using namespace' in psm1

Viewed 72

(PS 5.1) I put a using namespace directive in a psm1 to shorten some code. It then no longer recognizes a custom type I defined. Without the directive, all is peachy. It seems that a using namespace directive overrides things I did not expect it to.

Example: I have a main.ps1, and two modules.

main.ps1

using module .\classes.psm1 # using modules is needed to bring in classes, Import-Module won't cut it
Import-Module .\process.psm1 -Force # force reload
$MyList = Get-List # call function in module
$MyList[0].Bar # show a result

classes.psm1

Class Foo 
{
    [int]$Bar
}

process.psm1

function Get-List {
    $f = New-Object Foo
    $f.Bar = 42
    $list = [System.Collections.Generic.List[Foo]]::new()
    $list.Add($f)
    $list
}

This works fine. The trouble starts when I want to shorten things in process.psm1:

using namespace System.Collections.Generic

function Get-List {
    $f = New-Object Foo
    $f.Bar = 42
    $list = [List[Foo]]::new() # I just want a shorter way to declare a list
    $list.Add($f)
    $list
}

This complains about not recognizing type Foo. Why? (When I bring in using module .\classes.psm1 in process.psm1, all is fine again.)

My point/question is: how does using namespace affect a module's capability to recognize other modules/files within a 'solution'? It find it rather counter-intuitive, but I am not a PS expert.

1 Answers

By default, PowerShell defers type name resolution until runtime - unless a script file contains at least one of the following:

  • A using statement
  • A class definition
  • An enum definition

Without the using namespace System.Collections.Generic statement, PowerShell has no reason to attempt resolving any type names in process.psm1 until after [Foo] has been loaded from classes.psm1 and is resolvable/visible.

With the using ... statement on the other hand, PowerShell attempts to resolve the [Foo] type parameter in [List[Foo]] at parse-time - before process.psm1 has actually been loaded into main.ps1, and so the error you see is thrown.

As you've found, adding an explicit using module reference to the module file containing [Foo] solves it, as process.psm1 then no longer depends on the callers type resolution scope (which is not accessible at parse-time)

Related