Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Unable to Return [BindingList[RandomType]] from ScriptProperty

I have a complex class that dynamically adds members to itself based on a file loaded via Import-Clixml.

Boiling the class down to the problematic part leaves us with this (Take note of the commented line used to prove success up to that point):

class TestClass {
    [hashtable]$_data = @{}
    [void]DefineData([object]$data) {
        $this._data['Data'] = $data
        $this | Add-Member -MemberType ScriptProperty -Name 'ScriptProperty' -Value {
            #$this._data['Data'].GetType() | Out-Host
            return $this._data['Data']
        }
    }
}

In the following code, there are 4 statements for assigning a value to $OriginalValue. Leave 3 of these statements commented and uncomment the one you want to try. When executed, the code should result in $ReturnValue containing the same value as $OriginalValue, but in the case of assigning $OriginalValue an instance of [BindingList[RandomType]], $ReturnValue is $null.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

$ClassVar = [TestClass]::new()

$OriginalValue = [System.ComponentModel.BindingList[string]]::new()
#$OriginalValue = @{}
#$OriginalValue = [PSCustomObject]@{ Name = 'Value' }
#$OriginalValue = "Test String"

$OriginalValue.GetType()
$ClassVar.DefineData($OriginalValue)

$ReturnValue = $ClassVar.ScriptProperty
$ReturnValue.GetType()

Yes, I can hack my way around the problem by storing instances of [BindingList[RandomType]] in a [hashtable], but could someone explain what is going on, or even better yet, how to fix the code for all data types?

>Solution :

As explained in comments, the problem is not the BindingList but the output from your Script Block being enumerated. Since your BindingList has no elements when you call .DefineData($OriginalValue) then enumerating a list with no elements via .ScriptProperty results in null value:

(& { [System.ComponentModel.BindingList[string]]::new() }).GetType()

# Errors with:
# InvalidOperation: You cannot call a method on a null-valued expression.

A simple workaround is to wrap the output in a single element array before outputting, for this you can use the comma operator ,.

(& { , [System.ComponentModel.BindingList[string]]::new() }).GetType()

# Output type is preserved and the wrapping array is lost due to enumeration

So, your class method could look as follows considering the hashtable property is not needed:

class TestClass {
    [void] DefineData([object] $data) {
        $this.PSObject.Properties.Add(
            [psscriptproperty]::new(
                'ScriptProperty',
                { , $data }.GetNewClosure()
            )
        )
    }
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading