PowerShell classes still can't create value types

Created on 1 Oct 2019  路  7Comments  路  Source: PowerShell/PowerShell

Steps to reproduce

Try to implement any interfaces that is intended to be implemented in terms of yourself, E.g. IEquatable, IComparable:

class ServerName : Object, System.IEquatable[ServerName] {
    [string]$ComputerName
    [bool] Equals([ServerName]$other) {
        return $this.ComputerName.Equals($other.ComputerName);
    }
}

Expected behavior

I should be able to write IEquatable<T> and IComparable<T> classes 

Actual behavior

A runtime compile error:

An error occurred while creating the pipeline.
+ CategoryInfo          : NotSpecified: (:) [], ParentContainsErrorRecordException                                                                 + FullyQualifiedErrorId : RuntimeException                                  

Environment data

Any version of PowerShell since classes were introduced, up to and including 7 Pre 4

Issue-Question WG-Engine

Most helpful comment

@SeeminglyScience thanks. Believe it or not it totally worked :) Full code:

using namespace Microsoft.Management.Infrastructure
class CimObserver : System.IObserver[CimInstance] {
    [void] OnNext(
        [CimInstance]$ciminstance
    ) {
        write-host -fore green $cimInstance
    }
    [void] OnError([Exception]$Exception) {throw $exception}
    [void] OnCompleted() {$this.Unsubscribe()} 
}
$query = (new-cimsession).QueryInstancesAsync('root/cimv2','WQL','SELECT * FROM Win32_ComputerSystem')
$observer = new-object CimObserver
$query.subscribe($observer)

Outputted the textual representation in green to the host.

All 7 comments

It's obviously not the same, but just to mention an interim workaround: use [object] instead of your own type.

/cc @SeeminglyScience for reference #10623

Yeah this does repro without the specifics of #10623 (e.g. without the making the engine check overloads)

PS> Add-Type -IgnoreWarnings -TypeDefinition 'public interface ISomething<T> { }'
PS> class Test : ISomething[Test] { }
# At line:1 char:14
# + class Test : ISomething[Test] { }
# +              ~~~~~~~~~~~~~~~~
# Unable to find type [ISomething[Test]].
#     + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
#     + FullyQualifiedErrorId : TypeNotFound

Presumably because it's attempting type resolution without taking the current type definition into account.

Also about valuetypes (assuming the title wasn't a mistake) #10231 is also relevant.

This works. But shouldn't. And just like @mklement0 wrote, it's not the same as what you want, but a workaround. (I got seriously distracted going down the rabbit hole that is stuff not implemented by classes.)

Class ServerName: System.Collections.IEqualityComparer 
{
    [String] $ComputerName

    ServerName( [String] $serverName )
        {
            $this.ComputerName = $serverName
        }
    ServerName()
        {
            $this.ComputerName = ''
        }

    [Bool] Equals( $x, $y)  { return $x -eq $y        }
    [Bool] Equals( $x )     { return $this.ComputerName -eq $x }
    [Int] GetHashCode( $x ) { return $x.GetHashCode() }
}

$b = [ServerName]::new( 's1' )
$b -eq 's1'
$b -eq 's2'
$b.GetHashCode( $b )

EDIT: Was case sensitive per @SeeminglyScience, ignore for purposes of this issue

I came across this issue trying to implement IObserver for CIM to do get-ciminstance asynchronously basically.

using namespace Microsoft.Management.Infrastructure
class CimObserver : Iobserver[CimInstance] {
    [void] onNext(
        [CimInstance]$cimInstance
    ) {$null}
}
At line:2 char:1
+ class CimObserver : Iobserver[CimInstance] {
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Error during creation of type "CimObserver". Error message:
Method 'OnNext' in type 'CimObserver' from assembly 'PowerShell Class Assembly, Version=1.0.0.8, Culture=neutral, PublicKeyToken=null' does not have an implementation.

Unless someone can tell me what I'm doing wrong.

@JustinGrote Method names are case sensitive for declaration:

using namespace Microsoft.Management.Infrastructure

class CimObserver : IObserver[CimInstance] {
    [void] OnNext([CimInstance] $value) {}
    [void] OnError([Exception] $exception) {}
    [void] OnCompleted() {}
}

Though be aware that it's likely that OnNext will be called on a thread without a default runspace. If that's the case, the method will just throw.

@SeeminglyScience thanks. Believe it or not it totally worked :) Full code:

using namespace Microsoft.Management.Infrastructure
class CimObserver : System.IObserver[CimInstance] {
    [void] OnNext(
        [CimInstance]$ciminstance
    ) {
        write-host -fore green $cimInstance
    }
    [void] OnError([Exception]$Exception) {throw $exception}
    [void] OnCompleted() {$this.Unsubscribe()} 
}
$query = (new-cimsession).QueryInstancesAsync('root/cimv2','WQL','SELECT * FROM Win32_ComputerSystem')
$observer = new-object CimObserver
$query.subscribe($observer)

Outputted the textual representation in green to the host.

Was this page helpful?
0 / 5 - 0 ratings