I have been running into trouble adding new type accelerators in PS 5.1. I found this, and a few other similar references, so my understanding is that this is the case for all 5.# builds of PowerShell, not just the referenced preview. To that end, I have this
CLS
$accelerators = [PowerShell].Assembly.GetType("System.Management.Automation.TypeAccelerators")
$accelerators::Add("pxList",[System.Collections.Generic.List[string]])
$accelerators::Add("pxHashList",[System.Collections.Generic.List[hashtable]])
$builtinTypeAccelerators = $accelerators.GetField("builtinTypeAccelerators", [System.Reflection.BindingFlags]"Static,NonPublic")
$builtinTypeAccelerators.SetValue($builtinTypeAccelerators, $accelerators::Get)
class pxT_DefinitionsMigrater {
# Properties
$XML = [xml.xmlDocument]::new()
$Errors = [pxList]::new()
$initiations = [pxHashList]::new()
# Constructor
pxT_DefinitionsMigrater ([string]$xmlPath) {
}
}
[pxT_DefinitionsMigrater]::new('String')
And I am still getting Unable to find type errors. Where am I going wrong? Interestingly, this DOES work.
CLS
$accelerators = [PowerShell].Assembly.GetType("System.Management.Automation.TypeAccelerators")
$accelerators::Add("pxList",[System.Collections.Generic.List[string]])
$accelerators::Add("pxHashList",[System.Collections.Generic.List[hashtable]])
$builtinTypeAccelerators = $accelerators.GetField("builtinTypeAccelerators", [System.Reflection.BindingFlags]"Static,NonPublic")
$builtinTypeAccelerators.SetValue($builtinTypeAccelerators, $accelerators::Get)
([pxHashList]::new()).GetType().FullName
It seems that custom type accelerators don't work (the same way) with classes. So perhaps more importantly, is adding our own type accelerators still considered good practice, or is this change since PS5 an indication that we really shouldn't be doing it? Or at least not doing it in conjunction with classes?
Also, as an aside, but something that certainly doesn't warrant an actual question, I notice that the new method is not capitalized. When I get my intellisence options in the ISE for my new type Equals and ReferenceEquals are both capitalized, but new isn't. This is true for every new I have seen. Seems like there must be some useful information packaged in that fact.
EDIT: Very interesting discovery, just after my initial post. This also works
CLS
$accelerators = [PowerShell].Assembly.GetType("System.Management.Automation.TypeAccelerators")
$accelerators::Add("pxList",[System.Collections.Generic.List[string]])
$accelerators::Add("pxHashList",[System.Collections.Generic.List[hashtable]])
$builtinTypeAccelerators = $accelerators.GetField("builtinTypeAccelerators", [System.Reflection.BindingFlags]"Static,NonPublic")
$builtinTypeAccelerators.SetValue($builtinTypeAccelerators, $accelerators::Get)
class pxT_DefinitionsMigrater {
# Properties
$XML = [xml.xmlDocument]::new()
$Errors = $null
$initiations = $null
# Constructor
pxT_DefinitionsMigrater ([string]$xmlPath) {
$this.Errors = [pxList]::new()
$this.initiations = [pxHashList]::new()
}
}
[pxT_DefinitionsMigrater]::new('String')
So, the XML property can be assigned an actual value in the properties section, of an empty [xml.document], but I can't create new empty versions of my new types there, I need to do it in the ctor. Makes me wonder if there is an argument for always setting properties to $null at declaration, and then assigning a value in the constructor. So...
CLS
$accelerators = [PowerShell].Assembly.GetType("System.Management.Automation.TypeAccelerators")
$accelerators::Add("pxList",[System.Collections.Generic.List[string]])
$accelerators::Add("pxHashList",[System.Collections.Generic.List[hashtable]])
$builtinTypeAccelerators = $accelerators.GetField("builtinTypeAccelerators", [System.Reflection.BindingFlags]"Static,NonPublic")
$builtinTypeAccelerators.SetValue($builtinTypeAccelerators, $accelerators::Get)
class pxT_DefinitionsMigrater {
# Properties
[xml.xmlDocument]$XML = $null
[pxList]$Errors = $null
[pxHashList]$initiations = $null
# Constructor
pxT_DefinitionsMigrater ([string]$xmlPath) {
$this.XML = [xml.xmlDocument]::new()
$this.Errors = [pxList]::new()
$this.initiations = [pxHashList]::new()
}
}
[pxT_DefinitionsMigrater]::new('String')
If you have a number of ctor variations this seems a bit wasteful, but perhaps is best practice?
EDIT: Indeed, it seems it is second run that allows things to work, not where the accelerator is used. Given that this will eventually be a script and not run in the ISE, an answer that works in both places would be ideal.
$accelerators = [PowerShell].Assembly.GetType("System.Management.Automation.TypeAccelerators")
$accelerators::Add("pxList",[System.Collections.Generic.List[string]])
$accelerators::Add("pxHashList",[System.Collections.Generic.List[hashtable]])
$builtinTypeAccelerators = $accelerators.GetField("builtinTypeAccelerators", [System.Reflection.BindingFlags]"Static,NonPublic")
$builtinTypeAccelerators.SetValue($builtinTypeAccelerators, $accelerators::Get)
class pxT_DefinitionsMigrater {
# Properties
[xml.xmlDocument]$XML
[pxList]$Errors
[pxHashList]$initiations
# Constructor
[Void]initializeProperties () {
$this.XML = [xml.xmlDocument]::new()
$this.Errors = [pxList]::new()
$this.initiations = [pxHashList]::new()
}
pxT_DefinitionsMigrater ([string]$xmlPath) {
$this.initializeProperties()
}
}
[pxT_DefinitionsMigrater]::new('String')