Search code examples
powershellclassicomparer

Custom class comparer error: Specified method is not supported


I am trying to write a comparer for my own class. As I want everything to work in both Windows PowerShell (5.1) up till PowerShell 7, I am writing everything for Windows PowerShell first and then test PowerShell 7. Now suddenly the whole module doesn't load any more using module .\MyModule or using the Install-Module .\MyModule in PowerShell 7 and returns a general error:

Import-Module: Specified method is not supported.

After, removing everything that isn't related to the error, I have nailed the problem down to:

class MyClass {}

class MyComparer : Collections.Generic.IComparer[MyClass] {
    [String]$PrimaryKey # Should always become first
    [int] Compare ([MyClass]$Value1, [MyClass]$Value2) { return 0 }
}

Note that this (as my whole module) works fine in Windows PowerShell 5.1 and also:

  • When I remove the line: [String]$PrimaryKey # Should always become first
  • or when I change the item type from [MyClass] to e.g. [Object], like:
class MyComparer : Collections.Generic.IComparer[Object] {
    [String]$PrimaryKey # Should always be first
    [int] Compare ([Object]$Value1, [Object]$Value2) { return 0 }
}

This is really at the edge of what I understand of (comparer) interfaces and I wonder if I am actually doing something wrong here or whether this concerns a (PowerShell 7) bug...


Solution

  • This is just one of the many known issues that plague PowerShell class definitions (the meta issue tracking all class-related issues is GitHub issue #6652):

    In general, a notable limitation is that any .NET types (which PowerShell classes too are compiled to) referenced in class definitions (as well as param() blocks) must have been loaded before the code in question is parsed, which precedes actual execution.

    Additionally, it seems that classes defined in the same script or module file cannot reference themselves, such as in interface implementations - see GitHub issue #10669 - or each other - as in your case, a variation of which is reported in GitHub issue #20755

    It is curious that your specific code can at least be parsed in Windows PowerShell (whereas in PowerShell (Core) 7 it can only be parsed if the class defines no properties) but the following, simpler example yields the Specified method is not supported error in both editions:

    class MyItem { }
    
    # !! BREAKS, due to referencing [MyItem]
    class MyQueue : System.Collections.Generic.Queue[MyItem] { }
    

    The only obvious difference is that your attempt failed in the context of an interface implementation, whereas in this example it is a base-class specification.

    The workaround for now is to use [object] in lieu of MyClass, i.e., to implement System.Collections.Generic.IComparer[object] and to test the specific type identities at runtime.