Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1690,8 +1690,8 @@ private void HandleRemainingArguments()
// Set-ClusterOwnerNode -Owners foo,bar
// Set-ClusterOwnerNode foo bar
// Set-ClusterOwnerNode foo,bar
// we unwrap our List, but only if there is a single argument of type object[].
if (valueFromRemainingArguments.Count == 1 && valueFromRemainingArguments[0] is object[])
// we unwrap our List, but only if there is a single argument which is a collection.
if (valueFromRemainingArguments.Count == 1 && LanguagePrimitives.IsObjectEnumerable(valueFromRemainingArguments[0]))
{
cpi.SetArgumentValue(UnboundArguments[0].ArgumentExtent, valueFromRemainingArguments[0]);
}
Expand Down
37 changes: 17 additions & 20 deletions src/System.Management.Automation/engine/LanguagePrimitives.cs
Original file line number Diff line number Diff line change
Expand Up @@ -440,39 +440,36 @@ private static void InitializeGetEnumerableCache()

internal static bool IsTypeEnumerable(Type type)
{
if (type == null) { return false; }
GetEnumerableDelegate getEnumerable = GetOrCalculateEnumerable(type);
return (getEnumerable != LanguagePrimitives.ReturnNullEnumerable);
}

/// <summary>
/// Retrieves the IEnumerable of obj or null if the language does not consider obj to be IEnumerable
/// Returns True if the language considers obj to be IEnumerable
/// </summary>
/// <param name="obj">
/// IEnumerable or IEnumerable-like object
/// </param>
[SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "obj", Justification = "Since V1 code is already shipped, excluding this message.")]
public static IEnumerable GetEnumerable(object obj)
public static bool IsObjectEnumerable(object obj)
{
if (obj == null)
{
return null;
}

Type objectType = obj.GetType();
return IsTypeEnumerable(PSObject.Base(obj)?.GetType());
}

// if the object passed is an PSObject,
// look at the base object. Notice that, if the
// object has been serialized, the base object
// will be there as an ArrayList if the original
// object was IEnumerable
if (objectType == typeof(PSObject))
{
PSObject mshObj = (PSObject)obj;
obj = mshObj.BaseObject;
objectType = obj.GetType();
}

GetEnumerableDelegate getEnumerable = GetOrCalculateEnumerable(objectType);
/// <summary>
/// Retrieves the IEnumerable of obj or null if the language does not consider obj to be IEnumerable
/// </summary>
/// <param name="obj">
/// IEnumerable or IEnumerable-like object
/// </param>
[SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "obj", Justification = "Since V1 code is already shipped, excluding this message.")]
public static IEnumerable GetEnumerable(object obj)
{
obj = PSObject.Base(obj);
if (obj == null) { return null; }
GetEnumerableDelegate getEnumerable = GetOrCalculateEnumerable(obj.GetType());
return getEnumerable(obj);
}

Expand Down
20 changes: 20 additions & 0 deletions test/powershell/engine/ParameterBinding/ParameterBinding.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -422,5 +422,25 @@
$result.Value[1] | Should Be 2
$result.Value[2] | Should Be 3
}

It "Binds properly when collections of type other than object[] are used on an advanced function" {
$list = [Collections.Generic.List[int]](1..3)
$result = Test-BindingFunction $list

$result.ArgumentCount | Should Be 3
$result.Value[0] | Should Be 1
$result.Value[1] | Should Be 2
$result.Value[2] | Should Be 3
}

It "Binds properly when collections of type other than object[] are used on a cmdlet" {
$list = [Collections.Generic.List[int]](1..3)
$result = Test-BindingCmdlet $list

$result.ArgumentCount | Should Be 3
$result.Value[0] | Should Be 1
$result.Value[1] | Should Be 2
$result.Value[2] | Should Be 3
}
}
}