I am attempting to satisfy my curiosity about return type performance. Basically I want to see if there is a meaningful difference between a hash table, a psCustomObject and my own class when returning complex data. But I am having issues with the psCustomObject.
So, I started with
class pxObject {
[String]$String
[String]$Failure
[String]$Error
pxObject ([String]$string, [String]$failure, [String]$error) {
$this.String = $string
$this.Failure = $failure
$this.Error = $error
}
}
class pxReturn {
static [HashTable] Hash ([String]$string, [String]$failure, [String]$error) {
[HashTable]$returnHash = @{
String = $string
Failure = $failure
Error = $error
}
return $returnHash
}
static [psCustomObject] psObject ([String]$string, [String]$failure, [String]$error) {
[psCustomObject]$returnObject = [psCustomObject]@{
String = $string
Failure = $failure
Error = $error
}
return $returnObject
}
static [pxObject] pxObject ([String]$string, [String]$failure, [String]$error) {
[pxObject]$returnObject = [pxObject]::new($string, $failure, $error)
return $returnObject
}
}
[Int]$count = 1000
CLS
Write-Host 'Hash ' -NoNewLine
(Measure-Command {
foreach ($i in 1..$count) {
[pxReturn]::Hash("String $i", "Failure $i", "Error $i")
}
}).TotalSeconds
Write-Host 'psObject ' -NoNewLine
(Measure-Command {
foreach ($i in 1..$count) {
[pxReturn]::psObject("String $i", "Failure $i", "Error $i")
}
}).TotalSeconds
Write-Host 'pxObject ' -NoNewLine
(Measure-Command {
foreach ($i in 1..$count) {
[pxReturn]::pxObject("String $i", "Failure $i", "Error $i")
}
}).TotalSeconds
and I get Measure-Command : The given key was not present in the dictionary.
at the Measure-Command
line for the psObject test. Given that Measure-Command has a code block and that sometimes obscures the real error I revised that code to
Write-Host 'psObject ' -NoNewLine
#(Measure-Command {
foreach ($i in 1..$count) {
[pxReturn]::psObject("String $i", "Failure $i", "Error $i")
}
#}).TotalSeconds
and now I get An error occurred while creating the pipeline.
with no line info. This seems simple enough, so I am a bit stumped as to why it is failing. Especially since I copied the psCustomObject code from another project where it works fine. That's why the return data looks like it does, I have successfully used a psCustomObject for this very use case before.
EDIT: The one difference with what I had working and what I am trying to do is that before I was using functions. So I revised the above code to add a function that returns a psCustomObject, like so
function psObjectReturn ([String]$string, [String]$failure, [String]$error) {
[psCustomObject]$returnObject = [psCustomObject]@{
String = $string
Failure = $failure
Error = $error
}
return $returnObject
}
and added the appropriate test
Write-Host 'psObject (function) ' -NoNewLine
(Measure-Command {
foreach ($i in 1..$count) {
$test = psObjectReturn "String $i" "Failure $i" "Error $i"
}
}).TotalSeconds
That works a treat. But I am moving everything to classes so it doesn't really address the major question directly. Though it might if you simply CAN'T use [psCustomObject]
as the return type from a class method.
Also, performance is looking like this
Hash 0.01107
psObject (function) 0.0453963
pxObject 0.0245367
Which pretty much suggests Hash Tables are fastest, but not enough to make it mandatory, and I can make a decision between a Hash Table and my own class based on other criteria. But I am sure there is something interesting going on under the hood with the psObject from a class error.
The problem is your use of
psObject
as a method name, which conflicts with the hidden, intrinsic.psobject
property.A simplified reproduction of the problem:
Simply choosing a different method name resolves the issue: