What does T<T> (e.g. System.Collections.Queue<byte>) mean in Windows PowerShell

94 Views Asked by At

I had Windows PowerShell script that initialized a queue like this:

$queue = New-Object System.Collections.Queue<byte>

The code was working fine in Windows PowerShell, but it does not in PowerShell [Core]. It fails with

Cannot find type [System.Collections.Queue<byte>]: verify that the assembly containing this type is loaded.

When fixing the script for PowerShell [Core], I've realized that:

  1. System.Collections.Queue is not a generic type (System.Collections.Generic.Queue is).
  2. Generic type syntax in PowerShell is [], not <>.

So the correct code, both in Windows PowerShell and PowerShell [Core] is:

$queue = New-Object System.Collections.Generic.Queue[byte]

But now I wonder what was my original code actually doing. What magic is behind that? Is my new code a real equivalent of the original?

2

There are 2 best solutions below

0
mklement0 On BEST ANSWER

The magic is that Windows PowerShell simply quietly ignores the <byte> part; in fact, it doesn't matter what is inside < and >, and more generally, there are several characters that can start a suffix that is ignored, such as !, @ and %.

In other words: this is a bug, and it has since been fixed in PowerShell (Core) 7+, which properly interprets the whole argument as the type name.

And, as you note:

  • Generic type arguments always require enclosure in [...] in PowerShell as well as the underlying, language-agnostic .NET APIs.

    • [...] enclosure is also used for PowerShell's type literals, which are a superset of the notation understood by the .NET APIs, as discussed in this answer.

    • Because in v5+ the static ::new() method can be used on type literals as a method-syntax alternative to New-Object, your generic-queue construction command can also be written as:

      $queue = [System.Collections.Generic.Queue[byte]]::new()
      
      • This expression-mode way of calling constructors via ::new() is preferable to New-Object calls for several reasons:
        • It avoids the pitfalls of argument-mode parsing, especially with the frequently seen pseudo-method syntax - see this answer for an example.
        • It avoids the [psobject] wrappers that New-Object wraps newly constructed objects in, which are usually invisible and benign, but on occasion cause problems - see this answer for an example.
        • With repeated calls (such as in a loop), it performs better than New-Object
  • By contrast, the <...> syntax is language-specific, as notably used in C#.

0
JosefZ On

A type syntax in PowerShell is always [T], not <T>.

See e.g. Queue<T> Class… Here <> are meta brackets: in Microsoft conception,
<Text inside angle brackets> means a placeholder for which you must supply a value.

The following example comes from PowerShell 5 under wt.exe (Windows Terminal):

PS D:\PShell> [System.Collections.Generic.Queue
Comparer<>             IEqualityComparer<>    LinkedListNode<>
Dictionary<>           IList<>                List<>
EqualityComparer<>     IReadOnlyCollection<>  Queue<>
HashSet<>              IReadOnlyDictionary<>  SortedDictionary<>
ICollection<>          IReadOnlyList<>        SortedList<>
IComparer<>            ISet<>                 SortedSet<>
IDictionary<>          KeyNotFoundException   Stack<>
IEnumerable<>          KeyValuePair<>
IEnumerator<>          LinkedList<>

Class System.Collections.Generic.Queue[T]

As a picture:

enter image description here