Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is a plus operator required in some Powershell type names?

Why is it that, in Powershell, the System.DayOfWeek enum can be referred to like [System.DayOfWeek], whereas the System.Environment.SpecialFolder enum must be referred to like [System.Environment+SpecialFolder] (note the plus character)?

My guess is because SpecialFolder is part of the static Environment class and DayOfWeek is sitting directly in the System namespace, but I'm having trouble finding any information on this. Normally static members would use the "static member operator", but that doesn't work in this case, nor does anything else I try except the mysterious plus character...

[System.DayOfWeek] # returns enum type
[enum]::GetValues([System.DayOfWeek]) # returns enum values
[enum]::GetValues([System.Environment.SpecialFolder]) # exception: unable to find type
[enum]::GetValues([System.Environment]::SpecialFolder) # exception: value cannot be null
[enum]::GetValues([System.Environment+SpecialFolder]) # returns enum values

System.Environment.SpecialFolder is definitely a type, and in C# both enums work the same way:

Enum.GetValues(typeof(System.Environment.SpecialFolder)) // works fine
Enum.GetValues(typeof(System.DayOfWeek)) // also works

I'd really like to understand why there's a distinction in Powershell and the reasoning behind this behaviour. Does anyone know why this is the case?

like image 517
Matt Wanchap Avatar asked Jul 27 '19 01:07

Matt Wanchap


1 Answers

System.Environment.SpecialFolder is definitely a type

Type SpecialFolder, which is nested inside type Environment, is located in namespace System:

  • C# references that type as a full type name as in the quoted passage; that is, it uses . not only to separate the namespace from the containing type's name, but also to separate the latter from its nested type's name.

  • By contrast, PowerShell uses a .NET reflection method, Type.GetType(), to obtain a reference to the type at runtime:

    • That method uses a language-agnostic notation to identify types, as specified in documentation topic Specifying fully qualified type names.Tip of the hat to PetSerAl.

    • In that notation, it is + that is used to separate a nested type from its containing type (not ., as in C#).

That is, a PowerShell type literal ([...]) such as:

[System.Environment+SpecialFolder]

is effectively the same as taking the content between [ and ], System.Environment+SpecialFolder, and passing it as a string argument to Type.GetType, namely (expressed in PowerShell syntax):

[Type]::GetType('System.Environment+SpecialFolder')

Note that PowerShell offers convenient extensions (simplifications) to .NET's language-agnostic type notation, notably the ability to use PowerShell's type accelerators (such as [regex] for [System.Text.RegularExpressions.Regex]), the ability to omit the System. prefix from namespaces (e.g. [Collections.Generic.List`1[string]] instead of [System.Collections.Generic.List`1[string]]), and not having to specify the generic arity (e.g. `1) when a list of type argument is passed (e.g. [Collections.Generic.List[string]] instead of [Collections.Generic.List`1[string]] - see this answer) for more information.

like image 103
mklement0 Avatar answered Nov 17 '22 05:11

mklement0