PoshCode Archive  Artifact [9a209ce97e]

Artifact 9a209ce97e59228657a69f81db280a8b5827a59c51f33774e211060cba72e24c:

  • File Scalar-context.ps1 — part of check-in [ff21a259cf] at 2018-06-10 13:51:38 on branch trunk — Adds a scalar variables to the PowerShell type system. (user: Public domain size: 2050)

# encoding: ascii
# api: csharp
# title: Scalar context
# description: Adds a scalar variables to the PowerShell type system.
# version: 0.1
# type: class
# author: Public domain
# license: CC0
# x-poshcode-id: 5190
# x-archived: 2014-05-26T10:10:28
# x-published: 2014-05-24T03:45:00
#
#
<#

The problem with PowerShell is that it uses .NET's type system instead of its own.

In .NET, [object] is the top of the type hierarchy, [object[]] is below it and there is no common base class that all scalar types derive from.

This script is a hack that makes the PowerShell type system operate more like this:

                    [object]
           /                        \
     [scalar()]             any unravelable type with > 1 elements
   /     |     \            /          |        \
[int] [string] ...       [object[]] [arraylist] ...


$null and [AutomationNull]::Value are considered scalars
unravelable types with 0 or 1 elements are considered scalars and will be automatically unravelled

Basically:

[scalar()]$x = $rhs

is like:

$x, $null = $rhs

Except:
1. it fails if $rhs would unravel to more than 1 element rather than silently continuing
2. it preserves AutomationNull correctly unlike PowerShell

NOTE:
This only unravels 1 level deep.

#>

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

[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public sealed class ScalarAttribute : ArgumentTransformationAttribute {
	public override Object Transform(EngineIntrinsics engineIntrinsics, Object inputData) {
		System.Collections.IEnumerator enumerator = LanguagePrimitives.GetEnumerator(inputData);
		if (enumerator != null) {
			inputData = System.Management.Automation.Internal.AutomationNull.Value;
			for (int i = 0; enumerator.MoveNext();) {
				if (++i == 2)
					throw new ArgumentException("Sequence contains more than 1 element");
				inputData = enumerator.Current;
			}
		}
		return inputData;
		
	}
}
'@