# encoding: ascii
# api: csharp
# title: Dict context
# description: PowerShell has numeric and string contexts:
# version: 0.1
# type: class
# author: Public Domain
# license: CC0
# x-poshcode-id: 5178
# x-archived: 2014-05-24T12:12:27
# x-published: 2014-05-22T01:19:00
#
# [int]$a    = $null   # $a will be  0 instead of $null
# [string]$b = $null   # $b will be ‘’ instead of $null
# [dict()] does a similar thing for dictionaries:
# [dict()]$c = $null   # $c will be @{} instead of $null
#
<#

[dict()]$lhs = $rhs

Is basically equivalent to this pseudo-code:

$lhs = $(if ($null -eq $rhs) {
	@{}
} elseif ($rhs -is [System.Collections.IDictionary] -or $rhs -is [System.Collections.Generic.IDictionary`2] -or $rhs -is [System.Collections.Generic.IReadOnlyDictionary`2])) {
	$rhs
} else {
	throw ([ArgumentException]"Value is not a dictionary type")
})


Or in plain English, [dict()] converts $null to @{}, passes any [IDictionary]-like types as is, and fails otherwise.

NOTES:
PowerShell doesn't consider [IReadOnlyDictionary`2]s to be dictionaries, this code does.
PowerShell doesn't consider [IDictionary`2]s that don't implement [IDictionary] to be dictionaries, this code does.


#>

Add-Type -TypeDefinition @'
using System;
using System.Management.Automation;

[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class DictAttribute : ArgumentTransformationAttribute {
	public override Object Transform(EngineIntrinsics engineIntrinsics, Object inputData) {
		Object o = inputData;
		PSObject pso = inputData as PSObject;
		if (pso != null) {
			o = (pso != System.Management.Automation.Internal.AutomationNull.Value) ? pso.BaseObject : null;
		}
		if (o == null)
			return new System.Collections.Hashtable();
		if (o is System.Collections.IDictionary)
			return inputData;
		foreach (Type t in o.GetType().GetInterfaces()) {
			if (t.IsGenericType) {
				Type g = t.GetGenericTypeDefinition();
				if (g == typeof(System.Collections.Generic.IDictionary<,>) ||
				    g == typeof(System.Collections.Generic.IReadOnlyDictionary<,>))
				{
					return inputData;
				}
			}
		}
		throw new ArgumentException("Value is not a dictionary type");
	}
}
'@
