Skip to content

Commit 78cda51

Browse files
authored
Fix calling static properties or fields in non-static class (#874)
1 parent bc3ae26 commit 78cda51

File tree

3 files changed

+71
-7
lines changed

3 files changed

+71
-7
lines changed

src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs

+7-5
Original file line numberDiff line numberDiff line change
@@ -1920,11 +1920,12 @@ private bool TryFindPropertyOrField(Type type, string id, Expression? expression
19201920
switch (member)
19211921
{
19221922
case PropertyInfo property:
1923-
propertyOrFieldExpression = Expression.Property(expression, property);
1923+
var propertyIsStatic = property?.GetGetMethod().IsStatic ?? property?.GetSetMethod().IsStatic ?? false;
1924+
propertyOrFieldExpression = propertyIsStatic ? Expression.Property(null, property) : Expression.Property(expression, property);
19241925
return true;
19251926

19261927
case FieldInfo field:
1927-
propertyOrFieldExpression = Expression.Field(expression, field);
1928+
propertyOrFieldExpression = field.IsStatic ? Expression.Field(null, field) : Expression.Field(expression, field);
19281929
return true;
19291930

19301931
default:
@@ -2478,7 +2479,7 @@ private static Exception IncompatibleOperandsError(string opName, Expression lef
24782479
private MemberInfo? FindPropertyOrField(Type type, string memberName, bool staticAccess)
24792480
{
24802481
#if !(UAP10_0 || NETSTANDARD)
2481-
var extraBindingFlag = _parsingConfig.PrioritizePropertyOrFieldOverTheType && staticAccess ? BindingFlags.Static : BindingFlags.Instance;
2482+
var extraBindingFlag = _parsingConfig.PrioritizePropertyOrFieldOverTheType && staticAccess ? BindingFlags.Static : BindingFlags.Instance | BindingFlags.Static;
24822483
var bindingFlags = BindingFlags.Public | BindingFlags.DeclaredOnly | extraBindingFlag;
24832484
foreach (Type t in TypeHelper.GetSelfAndBaseTypes(type))
24842485
{
@@ -2492,11 +2493,12 @@ private static Exception IncompatibleOperandsError(string opName, Expression lef
24922493
}
24932494
return null;
24942495
#else
2495-
var isCaseSensitive = _parsingConfig?.IsCaseSensitive == true;
2496+
var isCaseSensitive = _parsingConfig.IsCaseSensitive == true;
24962497
foreach (Type t in TypeHelper.GetSelfAndBaseTypes(type))
24972498
{
24982499
// Try to find a property with the specified memberName
2499-
MemberInfo? member = t.GetTypeInfo().DeclaredProperties.FirstOrDefault(x => (!staticAccess || x.GetAccessors(true)[0].IsStatic) && ((x.Name == memberName) || (!isCaseSensitive && x.Name.Equals(memberName, StringComparison.OrdinalIgnoreCase))));
2500+
MemberInfo? member = t.GetTypeInfo().DeclaredProperties
2501+
.FirstOrDefault(x => (!staticAccess || x.GetAccessors(true)[0].IsStatic) && (x.Name == memberName || (!isCaseSensitive && x.Name.Equals(memberName, StringComparison.OrdinalIgnoreCase))));
25002502
if (member != null)
25012503
{
25022504
return member;

test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.MemberAccess.cs

+63-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using FluentAssertions;
1+
using System.Linq.Dynamic.Core.CustomTypeProviders;
2+
using FluentAssertions;
23
using Xunit;
34

45
namespace System.Linq.Dynamic.Core.Tests.Parser
@@ -21,6 +22,67 @@ public void ParseMemberAccess_DictionaryIndex_On_Dynamic()
2122
expression.ToString().Should().Be("System.Linq.Dynamic.Core.Tests.Parser.ProductDynamic[].Where(Param_0 => ([Dynamic] == Convert(\"First Product\", Object)))");
2223
#endif
2324
}
25+
26+
[Theory]
27+
[InlineData("Prop", "TestProp")]
28+
[InlineData("Field", "TestField")]
29+
public void Parse_StaticPropertyOrField_In_StaticClass1(string name, string value)
30+
{
31+
// Arrange
32+
var queryable = new int[1].AsQueryable();
33+
34+
// Act
35+
var result = queryable.Select<string>($"{typeof(StaticClassExample)}.{name}").First();
36+
37+
// Assert
38+
Assert.Equal(value, result);
39+
}
40+
41+
[Theory]
42+
[InlineData("Prop", "TestProp")]
43+
[InlineData("Field", "TestField")]
44+
public void Parse_StaticPropertyOrField_In_NonStaticClass1(string name, string value)
45+
{
46+
// Arrange
47+
var queryable = new int[1].AsQueryable();
48+
49+
// Act
50+
var result = queryable.Select<string>($"new {typeof(NonStaticClassExample)}().{name}").First();
51+
52+
// Assert
53+
Assert.Equal(value, result);
54+
}
55+
56+
[Theory]
57+
[InlineData("Prop", "TestProp")]
58+
[InlineData("Field", "TestField")]
59+
public void Parse_StaticPropertyOrField_In_NonStaticClass2(string name, string value)
60+
{
61+
// Arrange
62+
var queryable = new[] { new NonStaticClassExample() }.AsQueryable();
63+
64+
// Act
65+
var result = queryable.Select<string>(name).First();
66+
67+
// Assert
68+
Assert.Equal(value, result);
69+
}
70+
}
71+
72+
[DynamicLinqType]
73+
public class StaticClassExample
74+
{
75+
public static string Prop { get; set; } = "TestProp";
76+
77+
public static string Field = "TestField";
78+
}
79+
80+
[DynamicLinqType]
81+
public class NonStaticClassExample
82+
{
83+
public static string Prop { get; set; } = "TestProp";
84+
85+
public static string Field = "TestField";
2486
}
2587

2688
public class ProductDynamic

test/System.Linq.Dynamic.Core.Tests/SecurityTests.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ public void UsingStaticClassAsType_WhenAddedToDefaultDynamicLinqCustomTypeProvid
145145
action.Should().NotThrow();
146146
}
147147

148-
[Theory(Skip = "873")]
148+
[Theory]
149149
[InlineData("new System.Linq.Dynamic.Core.Tests.Helpers.Models.AppSettings3()", "SettingsProp[\"jwt\"]")]
150150
[InlineData("new System.Linq.Dynamic.Core.Tests.Helpers.Models.AppSettings3()", "SettingsField[\"jwt\"]")]
151151
[InlineData("c => new System.Linq.Dynamic.Core.Tests.Helpers.Models.AppSettings3()", "SettingsProp[\"jwt\"]")]

0 commit comments

Comments
 (0)