11// Copyright (c) Microsoft Corporation.
22// Licensed under the MIT License.
33
4+ using System . Buffers ;
45using System . Collections ;
56using System . Collections . Concurrent ;
67using System . Collections . Generic ;
@@ -6533,6 +6534,14 @@ public override DynamicMetaObject FallbackInvoke(DynamicMetaObject target, Dynam
65336534
65346535 internal sealed class PSInvokeMemberBinder : InvokeMemberBinder
65356536 {
6537+ private static readonly SearchValues < string > s_whereSearchValues = SearchValues . Create (
6538+ [ "Where" , "PSWhere" ] ,
6539+ StringComparison . OrdinalIgnoreCase ) ;
6540+
6541+ private static readonly SearchValues < string > s_foreachSearchValues = SearchValues . Create (
6542+ [ "ForEach" , "PSForEach" ] ,
6543+ StringComparison . OrdinalIgnoreCase ) ;
6544+
65366545 internal enum MethodInvocationType
65376546 {
65386547 Ordinary ,
@@ -6681,12 +6690,14 @@ public override DynamicMetaObject FallbackInvokeMember(DynamicMetaObject target,
66816690 . WriteToDebugLog ( this ) ;
66826691 BindingRestrictions argRestrictions = args . Aggregate ( BindingRestrictions . Empty , static ( current , arg ) => current . Merge ( arg . PSGetMethodArgumentRestriction ( ) ) ) ;
66836692
6684- if ( string . Equals ( Name , "Where" , StringComparison . OrdinalIgnoreCase ) )
6693+ // We need to pass the empty enumerator to the ForEach/Where operators, so that they can return an empty collection.
6694+ // The ForEach/Where operators will not be able to call the script block if the enumerator is empty.
6695+ if ( s_whereSearchValues . Contains ( Name ) )
66856696 {
66866697 return InvokeWhereOnCollection ( emptyEnumerator , args , argRestrictions ) . WriteToDebugLog ( this ) ;
66876698 }
66886699
6689- if ( string . Equals ( Name , "ForEach" , StringComparison . OrdinalIgnoreCase ) )
6700+ if ( s_foreachSearchValues . Contains ( Name ) )
66906701 {
66916702 return InvokeForEachOnCollection ( emptyEnumerator , args , argRestrictions ) . WriteToDebugLog ( this ) ;
66926703 }
@@ -6866,12 +6877,12 @@ public override DynamicMetaObject FallbackInvokeMember(DynamicMetaObject target,
68666877 if ( ! _static && ! _nonEnumerating && target . Value != AutomationNull . Value )
68676878 {
68686879 // Invoking Where and ForEach operators on collections.
6869- if ( string . Equals ( Name , "Where" , StringComparison . OrdinalIgnoreCase ) )
6880+ if ( s_whereSearchValues . Contains ( Name ) )
68706881 {
68716882 return InvokeWhereOnCollection ( target , args , restrictions ) . WriteToDebugLog ( this ) ;
68726883 }
68736884
6874- if ( string . Equals ( Name , "ForEach" , StringComparison . OrdinalIgnoreCase ) )
6885+ if ( s_foreachSearchValues . Contains ( Name ) )
68756886 {
68766887 return InvokeForEachOnCollection ( target , args , restrictions ) . WriteToDebugLog ( this ) ;
68776888 }
@@ -7490,7 +7501,7 @@ internal static object InvokeAdaptedMember(object obj, string methodName, object
74907501 // As a last resort, we invoke 'Where' and 'ForEach' operators on singletons like
74917502 // ([pscustomobject]@{ foo = 'bar' }).Foreach({$_})
74927503 // ([pscustomobject]@{ foo = 'bar' }).Where({1})
7493- if ( string . Equals ( methodName , "Where" , StringComparison . OrdinalIgnoreCase ) )
7504+ if ( s_whereSearchValues . Contains ( methodName ) )
74947505 {
74957506 var enumerator = ( new object [ ] { obj } ) . GetEnumerator ( ) ;
74967507 switch ( args . Length )
@@ -7506,7 +7517,7 @@ internal static object InvokeAdaptedMember(object obj, string methodName, object
75067517 }
75077518 }
75087519
7509- if ( string . Equals ( methodName , "Foreach" , StringComparison . OrdinalIgnoreCase ) )
7520+ if ( s_foreachSearchValues . Contains ( methodName ) )
75107521 {
75117522 var enumerator = ( new object [ ] { obj } ) . GetEnumerator ( ) ;
75127523 object [ ] argsToPass ;
0 commit comments