PowerShell makes a hard-coded exception for types that implement the non-generic System.Collections.IDictionary interface with respect to behavior in the pipeline: even though such types are enumerable, PowerShell sends them as a whole through the pipeline.
Source code here:
|
private static GetEnumerableDelegate CalculateGetEnumerable(Type objectType) |
|
{ |
|
if (typeof(DataTable).IsAssignableFrom(objectType)) |
|
{ |
|
return LanguagePrimitives.DataTableEnumerable; |
|
} |
|
|
|
// Don't treat IDictionary or XmlNode as enumerable... |
|
if (typeof(IEnumerable).IsAssignableFrom(objectType) |
|
&& !typeof(IDictionary).IsAssignableFrom(objectType) |
|
&& !typeof(XmlNode).IsAssignableFrom(objectType)) |
|
{ |
|
return LanguagePrimitives.TypicalEnumerable; |
|
} |
|
|
|
return LanguagePrimitives.ReturnNullEnumerable; |
|
} |
|
|
|
private static readonly CallSite<Func<CallSite, object, IEnumerator>> s_getEnumeratorSite = |
|
CallSite<Func<CallSite, object, IEnumerator>>.Create(PSEnumerableBinder.Get()); |
|
|
However, some types only implement the generic equivalent of this interface, System.Collections.Generic.IDictionary<TKey, TValue>.
Such type are therefore unexpectedly enumerated in the pipeline, i.e their key-value pairs are sent rather than the dictionary itself.
Note that while with the IEnumerable / IEnumerable<Type> interface pair implementing the generic version implicitly also implements the non-generic one, this does not apply to the IDictionary / IDictionary<TKey, TValue> pair.
I don't know what the official recommendations are in this case, but at least one notable example of a type that only implements the generic interface is System.Dynamic.ExpandoObject, used in the repro below.
Steps to reproduce
$o = [System.Dynamic.ExpandoObject]::new(); $o.one = 1; $o.two = 2
($o | Measure-Object).Count | Should -Be 1
Expected behavior
The test should succeed: the IDictionary2`-implementing type's instance should be sent as a whole through the pipeline.
Actual behavior
The test fails, because the instance is enumerated and its key-value pairs are sent through the pipeline.
InvalidResult: Expected 1, but got 2.
Environment data
PowerShell Core 7.2.0-preview.4
PowerShell makes a hard-coded exception for types that implement the non-generic
System.Collections.IDictionaryinterface with respect to behavior in the pipeline: even though such types are enumerable, PowerShell sends them as a whole through the pipeline.Source code here:
PowerShell/src/System.Management.Automation/engine/LanguagePrimitives.cs
Lines 523 to 543 in 48c7e11
However, some types only implement the generic equivalent of this interface,
System.Collections.Generic.IDictionary<TKey, TValue>.Such type are therefore unexpectedly enumerated in the pipeline, i.e their key-value pairs are sent rather than the dictionary itself.
Note that while with the
IEnumerable/IEnumerable<Type>interface pair implementing the generic version implicitly also implements the non-generic one, this does not apply to theIDictionary/IDictionary<TKey, TValue>pair.I don't know what the official recommendations are in this case, but at least one notable example of a type that only implements the generic interface is
System.Dynamic.ExpandoObject, used in the repro below.Steps to reproduce
Expected behavior
The test should succeed: the
IDictionary2`-implementing type's instance should be sent as a whole through the pipeline.Actual behavior
The test fails, because the instance is enumerated and its key-value pairs are sent through the pipeline.
Environment data