From f043954ba725119e61516e1bd3cbfaf621a14b5e Mon Sep 17 00:00:00 2001 From: abdullah kara Date: Tue, 9 Sep 2025 18:37:21 +0300 Subject: [PATCH] Add AllowAccessToNonPublicMembers property to ParsingConfig This new property allows the parser to consider non-public members during property/field lookups when access is permitted. Updated ExpressionParser to utilize this configuration for member visibility during lookups.a --- .../Parser/ExpressionParser.cs | 17 ++++++++++++----- src/System.Linq.Dynamic.Core/ParsingConfig.cs | 7 +++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs index a43b534e..a866c748 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs @@ -1909,7 +1909,7 @@ private Expression ParseMemberAccess(Type? type, Expression? expression, string? return Expression.MakeIndex(expression, typeof(DynamicClass).GetProperty("Item"), new[] { Expression.Constant(id) }); } #endif - if (TryFindPropertyOrField(type!, id, expression, out var propertyOrFieldExpression)) + if (TryFindPropertyOrField(type!, id, expression, out var propertyOrFieldExpression)) { return propertyOrFieldExpression; } @@ -1954,7 +1954,9 @@ private bool TryFindPropertyOrField(Type type, string id, Expression? expression switch (member) { case PropertyInfo property: - var propertyIsStatic = property?.GetGetMethod().IsStatic ?? property?.GetSetMethod().IsStatic ?? false; + var getter = property.GetGetMethod(true); + var setter = property.GetSetMethod(true); + var propertyIsStatic = (getter?.IsStatic == true) || (setter?.IsStatic == true); propertyOrFieldExpression = propertyIsStatic ? Expression.Property(null, property) : Expression.Property(expression, property); return true; @@ -2514,7 +2516,8 @@ private static Exception IncompatibleOperandsError(string opName, Expression lef { #if !(UAP10_0 || NETSTANDARD) var extraBindingFlag = _parsingConfig.PrioritizePropertyOrFieldOverTheType && staticAccess ? BindingFlags.Static : BindingFlags.Instance | BindingFlags.Static; - var bindingFlags = BindingFlags.Public | BindingFlags.DeclaredOnly | extraBindingFlag; + var visibilityFlags = BindingFlags.Public | (_parsingConfig.AllowAccessToNonPublicMembers ? BindingFlags.NonPublic : 0); + var bindingFlags = visibilityFlags | BindingFlags.DeclaredOnly | extraBindingFlag; foreach (Type t in TypeHelper.GetSelfAndBaseTypes(type)) { var findMembersType = _parsingConfig?.IsCaseSensitive == true ? Type.FilterName : Type.FilterNameIgnoreCase; @@ -2532,14 +2535,18 @@ private static Exception IncompatibleOperandsError(string opName, Expression lef { // Try to find a property with the specified memberName MemberInfo? member = t.GetTypeInfo().DeclaredProperties - .FirstOrDefault(x => (!staticAccess || x.GetAccessors(true)[0].IsStatic) && (x.Name == memberName || (!isCaseSensitive && x.Name.Equals(memberName, StringComparison.OrdinalIgnoreCase)))); + .FirstOrDefault(x => (!staticAccess || x.GetAccessors(true)[0].IsStatic) + && (x.Name == memberName || (!isCaseSensitive && x.Name.Equals(memberName, StringComparison.OrdinalIgnoreCase))) + && (_parsingConfig.AllowAccessToNonPublicMembers || x.GetAccessors(true).Any(a => a.IsPublic))); if (member != null) { return member; } // If no property is found, try to get a field with the specified memberName - member = t.GetTypeInfo().DeclaredFields.FirstOrDefault(x => (!staticAccess || x.IsStatic) && ((x.Name == memberName) || (!isCaseSensitive && x.Name.Equals(memberName, StringComparison.OrdinalIgnoreCase)))); + member = t.GetTypeInfo().DeclaredFields.FirstOrDefault(x => (!staticAccess || x.IsStatic) + && ((x.Name == memberName) || (!isCaseSensitive && x.Name.Equals(memberName, StringComparison.OrdinalIgnoreCase))) + && (_parsingConfig.AllowAccessToNonPublicMembers || x.IsPublic)); if (member != null) { return member; diff --git a/src/System.Linq.Dynamic.Core/ParsingConfig.cs b/src/System.Linq.Dynamic.Core/ParsingConfig.cs index 300ff594..f22097f0 100644 --- a/src/System.Linq.Dynamic.Core/ParsingConfig.cs +++ b/src/System.Linq.Dynamic.Core/ParsingConfig.cs @@ -319,4 +319,11 @@ public IQueryableAnalyzer QueryableAnalyzer /// Default value is false. /// public bool AllowEqualsAndToStringMethodsOnObject { get; set; } + + /// + /// When set to true, the parser will consider non-public members (internal and private) + /// during property/field lookup where the runtime permits access (e.g., via InternalsVisibleTo). + /// Default value is false. + /// + public bool AllowAccessToNonPublicMembers { get; set; } } \ No newline at end of file