11#if ! NET35  &&  ! UAP10_0  &&  ! NETSTANDARD1_3 
22using  System . Collections ; 
3+ using  System . Collections . Concurrent ; 
34using  System . Collections . Generic ; 
45using  System . Dynamic ; 
56using  System . Linq . Expressions ; 
@@ -15,7 +16,15 @@ internal class DynamicGetMemberBinder : GetMemberBinder
1516{ 
1617    private  static readonly  MethodInfo  DynamicGetMemberMethod  =  typeof ( DynamicGetMemberBinder ) . GetMethod ( nameof ( GetDynamicMember ) ) ! ; 
1718
18-     public  DynamicGetMemberBinder ( string  name ,  ParsingConfig ?  config )  :  base ( name ,  config ? . IsCaseSensitive  !=  true ) 
19+     // The _metaObjectCache uses a Tuple<Type, string, bool> as the key to cache DynamicMetaObject instances. 
20+     // The key components are: 
21+     // - Type: The LimitType of the target object, ensuring type-specific caching. 
22+     // - string: The member name being accessed. 
23+     // - bool: The IgnoreCase flag, indicating whether the member name comparison is case-insensitive. 
24+     // This strategy ensures that the cache correctly handles different types, member names, and case-sensitivity settings. 
25+     private  readonly  ConcurrentDictionary < Tuple < Type ,  string ,  bool > ,  DynamicMetaObject >  _metaObjectCache  =  new ( ) ; 
26+ 
27+     internal  DynamicGetMemberBinder ( string  name ,  ParsingConfig ?  config )  :  base ( name ,  config ? . IsCaseSensitive  !=  true ) 
1928    { 
2029    } 
2130
@@ -28,8 +37,20 @@ public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, Dy
2837            Expression . Constant ( IgnoreCase ) ) ; 
2938
3039        // Fix #907 and #912: "The result of the dynamic binding produced by the object with type '<>f__AnonymousType1`4' for the binder 'System.Linq.Dynamic.Core.DynamicGetMemberBinder' needs at least one restriction.". 
31-         var  restrictions  =  BindingRestrictions . GetInstanceRestriction ( target . Expression ,  target . Value ) ; 
32-         return  new  DynamicMetaObject ( methodCallExpression ,  restrictions ,  target . Value ! ) ; 
40+         // Fix #921: "Slow Performance" 
41+         // Only add TypeRestriction if it's a Dynamic type and make sure to cache the DynamicMetaObject. 
42+         if  ( target . Value  is  IDynamicMetaObjectProvider ) 
43+         { 
44+             var  key  =  new  Tuple < Type ,  string ,  bool > ( target . LimitType ,  Name ,  IgnoreCase ) ; 
45+ 
46+             return  _metaObjectCache . GetOrAdd ( key ,  _ => 
47+             { 
48+                 var  restrictions  =  BindingRestrictions . GetTypeRestriction ( target . Expression ,  target . LimitType ) ; 
49+                 return  new  DynamicMetaObject ( methodCallExpression ,  restrictions ,  target . Value ) ; 
50+             } ) ; 
51+         } 
52+ 
53+         return  DynamicMetaObject . Create ( target . Value ! ,  methodCallExpression ) ; 
3354    } 
3455
3556    public  static object ?  GetDynamicMember ( object  value ,  string  name ,  bool  ignoreCase ) 
0 commit comments