How come I can create objects with the type accelerator [pscustomobject] but not its fullname, [System.Management.Automation.PSCustomObject]? Is there some magical constructor I'm not accessing?
$a = [pscustomobject]@{name='joe'}
$a.gettype().fullname
System.Management.Automation.PSCustomObject
[System.Management.Automation.PSCustomObject]@{name='joe'}
InvalidArgument: Cannot convert the "System.Collections.Hashtable" value of type "System.Collections.Hashtable" to type "System.Management.Automation.PSCustomObject".
Or I can try [System.Management.Automation.PSObject], but I just get a hashtable:
[psobject].Assembly.GetType('System.Management.Automation.TypeAccelerators')::get.pscustomobject.fullname
System.Management.Automation.PSObject
[System.Management.Automation.PSObject]@{name='joe'}
Name Value
---- -----
name joe
Inspired by this thread: https://powershell.org/forums/topic/type-accelerator
Is there some magical constructor I'm not accessing?
No, there's magic sauce in the compiler - whenever the PowerShell compiler sees a cast expression where the right-hand side is a dictionary and the type literal has the exact name pscustomobject
, it'll treat the dictionary or hashtable (whether literal or not) as an ordered dictionary and convert it to a PSObject
.
From VisitConvertExpression
in Compiler.cs:
var typeName = convertExpressionAst.Type.TypeName;
var hashTableAst = convertExpressionAst.Child as HashtableAst;
Expression childExpr = null;
if (hashTableAst != null)
{
var temp = NewTemp(typeof(OrderedDictionary), "orderedDictionary");
if (typeName.FullName.Equals(LanguagePrimitives.OrderedAttribute, StringComparison.OrdinalIgnoreCase))
{
return Expression.Block(
typeof(OrderedDictionary),
new[] { temp },
BuildHashtable(hashTableAst.KeyValuePairs, temp, ordered: true));
}
if (typeName.FullName.Equals("PSCustomObject", StringComparison.OrdinalIgnoreCase))
{
// pure laziness here - we should construct the PSObject directly. Instead, we're relying on the conversion
// to create the PSObject from an OrderedDictionary.
childExpr = Expression.Block(
typeof(OrderedDictionary),
new[] { temp },
BuildHashtable(hashTableAst.KeyValuePairs, temp, ordered: true));
}
}
Notice how this is also how [ordered]@{Key='Value'}
results in an OrderedDictionary