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 const string WhereMagicMethodName = "Where" ;
6538+ private const string WhereMagicMethodPSName = $ "PS{ WhereMagicMethodName } ";
6539+ private const string ForeachMagicMethodName = "Foreach" ;
6540+ private const string ForeachMagicMethodPSName = $ "PS{ ForeachMagicMethodName } ";
6541+
6542+ private static readonly SearchValues < string > s_whereSearchValues = SearchValues . Create ( [ WhereMagicMethodName , WhereMagicMethodPSName ] , StringComparison . OrdinalIgnoreCase ) ;
6543+ private static readonly SearchValues < string > s_foreachSearchValues = SearchValues . Create ( [ ForeachMagicMethodName , ForeachMagicMethodPSName ] , StringComparison . OrdinalIgnoreCase ) ;
6544+
65366545 internal enum MethodInvocationType
65376546 {
65386547 Ordinary ,
@@ -6681,12 +6690,16 @@ 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+ if ( string . Equals ( Name , WhereMagicMethodName , StringComparison . OrdinalIgnoreCase )
6694+ || string . Equals ( Name , WhereMagicMethodPSName , StringComparison . OrdinalIgnoreCase ) )
66856695 {
66866696 return InvokeWhereOnCollection ( emptyEnumerator , args , argRestrictions ) . WriteToDebugLog ( this ) ;
66876697 }
66886698
6689- if ( string . Equals ( Name , "ForEach" , StringComparison . OrdinalIgnoreCase ) )
6699+ if ( string . Equals ( Name , "Foreach" , StringComparison . OrdinalIgnoreCase )
6700+ || string . Equals ( Name , "PSForeach" , StringComparison . OrdinalIgnoreCase ) )
6701+ // We need to pass the empty enumerator to the ForEach operator, so that it can return an empty collection.
6702+ // The ForEach operator will not be able to call the script block if the enumerator is empty.
66906703 {
66916704 return InvokeForEachOnCollection ( emptyEnumerator , args , argRestrictions ) . WriteToDebugLog ( this ) ;
66926705 }
@@ -6866,12 +6879,12 @@ public override DynamicMetaObject FallbackInvokeMember(DynamicMetaObject target,
68666879 if ( ! _static && ! _nonEnumerating && target . Value != AutomationNull . Value )
68676880 {
68686881 // Invoking Where and ForEach operators on collections.
6869- if ( string . Equals ( Name , "Where" , StringComparison . OrdinalIgnoreCase ) )
6882+ if ( s_whereSearchValues . Contains ( Name ) )
68706883 {
68716884 return InvokeWhereOnCollection ( target , args , restrictions ) . WriteToDebugLog ( this ) ;
68726885 }
68736886
6874- if ( string . Equals ( Name , "ForEach" , StringComparison . OrdinalIgnoreCase ) )
6887+ if ( s_foreachSearchValues . Contains ( Name ) )
68756888 {
68766889 return InvokeForEachOnCollection ( target , args , restrictions ) . WriteToDebugLog ( this ) ;
68776890 }
@@ -7490,7 +7503,7 @@ internal static object InvokeAdaptedMember(object obj, string methodName, object
74907503 // As a last resort, we invoke 'Where' and 'ForEach' operators on singletons like
74917504 // ([pscustomobject]@{ foo = 'bar' }).Foreach({$_})
74927505 // ([pscustomobject]@{ foo = 'bar' }).Where({1})
7493- if ( string . Equals ( methodName , "Where" , StringComparison . OrdinalIgnoreCase ) )
7506+ if ( s_whereSearchValues . Contains ( methodName ) )
74947507 {
74957508 var enumerator = ( new object [ ] { obj } ) . GetEnumerator ( ) ;
74967509 switch ( args . Length )
@@ -7506,7 +7519,7 @@ internal static object InvokeAdaptedMember(object obj, string methodName, object
75067519 }
75077520 }
75087521
7509- if ( string . Equals ( methodName , "Foreach" , StringComparison . OrdinalIgnoreCase ) )
7522+ if ( s_foreachSearchValues . Contains ( methodName ) )
75107523 {
75117524 var enumerator = ( new object [ ] { obj } ) . GetEnumerator ( ) ;
75127525 object [ ] argsToPass ;
0 commit comments