From 48ed1521b9120265d8430383da109d7c742a0218 Mon Sep 17 00:00:00 2001 From: jonasdaniels Date: Wed, 24 Nov 2021 14:30:26 +0100 Subject: [PATCH 1/5] bind expressions to correct constructor parameter --- .../Parser/ExpressionParser.cs | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs index 2f068add..ff5ecb85 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs @@ -1466,20 +1466,25 @@ private Expression CreateNewExpression(List properties, List p.PropertyType).ToArray(); ConstructorInfo ctor = type.GetConstructor(propertyTypes); - if (ctor != null && ctor.GetParameters().Length == expressions.Count) + if (ctor != null) { - var expressionsPromoted = new List(); - - // Loop all expressions and promote if needed - for (int i = 0; i < propertyTypes.Length; i++) + var ctorParameters = ctor.GetParameters(); + if (ctorParameters.Length == expressions.Count) { - Type propertyType = propertyTypes[i]; + var expressionsPromoted = new List(); + // Loop all expressions and promote if needed + for (int i = 0; i < ctorParameters.Length; i++) + { + Type propertyType = ctorParameters[i].ParameterType; + string cParameterName = ctorParameters[i].Name; + var propertyAndIndex = properties.Select((p, index) => new { p, index }) + .First(p => p.p.Name == cParameterName && p.p.Type == propertyType); + // Promote from Type to Nullable Type if needed + expressionsPromoted.Add(_parsingConfig.ExpressionPromoter.Promote(expressions[propertyAndIndex.index], propertyType, true, true)); + } - // Promote from Type to Nullable Type if needed - expressionsPromoted.Add(_parsingConfig.ExpressionPromoter.Promote(expressions[i], propertyType, true, true)); + return Expression.New(ctor, expressionsPromoted, (IEnumerable)propertyInfos); } - - return Expression.New(ctor, expressionsPromoted, (IEnumerable)propertyInfos); } MemberBinding[] bindings = new MemberBinding[properties.Count]; From 277989631e4179655312459a9de8015fac7beda8 Mon Sep 17 00:00:00 2001 From: jonasdaniels Date: Thu, 25 Nov 2021 14:29:54 +0100 Subject: [PATCH 2/5] dynamic type test --- .../ExpressionParserTests.TypeAccess.cs | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.TypeAccess.cs b/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.TypeAccess.cs index 7d77d466..9c26a55a 100644 --- a/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.TypeAccess.cs +++ b/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.TypeAccess.cs @@ -1,4 +1,5 @@ -using System.Linq.Dynamic.Core.Parser; +using System.Collections.Generic; +using System.Linq.Dynamic.Core.Parser; using System.Linq.Expressions; using FluentAssertions; using Xunit; @@ -97,5 +98,28 @@ public void ParseTypeAccess_Via_Constructor_String_And_UriKind_To_Uri() // Assert expression.ToString().Should().Be("new Uri(\"https://www.example.com/\", Absolute)"); } + + [Theory] + [InlineData("new(2 as b, 1 as a)", "new(1 as a, 2 as b)")] + public void ParseTypeAccess_Via_Constructor_DynamicType_To_String(string newExpression, string newExpression2) + { + // Arrange + var parameter = Expression.Parameter(typeof(int)); + var parameter2 = Expression.Parameter(typeof(int)); + var returnType = DynamicClassFactory.CreateType(new List { + new DynamicProperty("a", typeof(int)), + new DynamicProperty("b", typeof(int)) + }); + + // Act + var parser = new ExpressionParser(new[] { parameter, parameter2 }, newExpression, new object[] { }, ParsingConfig.Default); + var parser2 = new ExpressionParser(new[] { parameter, parameter2 }, newExpression2, new object[] { }, ParsingConfig.Default); + + var expression = parser.Parse(returnType); + var expression2 = parser2.Parse(returnType); + // Assert + expression.ToString().Should().Be("new "+ returnType.Name + "(a = 1, b = 2)"); + expression2.ToString().Should().Be("new "+ returnType.Name + "(a = 1, b = 2)"); + } } } From 308c41dbf0aba9011e03622c5583e6a6879f1af6 Mon Sep 17 00:00:00 2001 From: jonasdaniels Date: Thu, 25 Nov 2021 18:47:22 +0100 Subject: [PATCH 3/5] linedata --- .../Parser/ExpressionParserTests.TypeAccess.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.TypeAccess.cs b/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.TypeAccess.cs index 9c26a55a..c5bed90c 100644 --- a/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.TypeAccess.cs +++ b/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.TypeAccess.cs @@ -100,7 +100,8 @@ public void ParseTypeAccess_Via_Constructor_String_And_UriKind_To_Uri() } [Theory] - [InlineData("new(2 as b, 1 as a)", "new(1 as a, 2 as b)")] + [InlineData("new(1 as a, 2 as b)", "new*(a = 1, b = 2)")] + [InlineData("new(2 as b, 1 as a)", "new*(a = 1, b = 2)")] public void ParseTypeAccess_Via_Constructor_DynamicType_To_String(string newExpression, string newExpression2) { // Arrange @@ -113,13 +114,10 @@ public void ParseTypeAccess_Via_Constructor_DynamicType_To_String(string newExpr // Act var parser = new ExpressionParser(new[] { parameter, parameter2 }, newExpression, new object[] { }, ParsingConfig.Default); - var parser2 = new ExpressionParser(new[] { parameter, parameter2 }, newExpression2, new object[] { }, ParsingConfig.Default); var expression = parser.Parse(returnType); - var expression2 = parser2.Parse(returnType); // Assert - expression.ToString().Should().Be("new "+ returnType.Name + "(a = 1, b = 2)"); - expression2.ToString().Should().Be("new "+ returnType.Name + "(a = 1, b = 2)"); + expression.ToString().Should().Match(newExpression2); } } } From 2aded474d15060ed1022475e46d1c266b843989d Mon Sep 17 00:00:00 2001 From: "DESKTOP-PP5PE2H\\jonas" Date: Mon, 29 Nov 2021 13:06:05 +0100 Subject: [PATCH 4/5] fix Select_Dynamic_IntoTypeWithNullableProperties2 test --- .../Parser/ExpressionParser.cs | 2 +- .../QueryableTests.Select.cs | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs index ff5ecb85..71141b2a 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs @@ -1478,7 +1478,7 @@ private Expression CreateNewExpression(List properties, List new { p, index }) - .First(p => p.p.Name == cParameterName && p.p.Type == propertyType); + .First(p => p.p.Name == cParameterName && (p.p.Type == propertyType || p.p.Type == Nullable.GetUnderlyingType(propertyType))); // Promote from Type to Nullable Type if needed expressionsPromoted.Add(_parsingConfig.ExpressionPromoter.Promote(expressions[propertyAndIndex.index], propertyType, true, true)); } diff --git a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Select.cs b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Select.cs index a0873b4a..9e8ba954 100644 --- a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Select.cs +++ b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Select.cs @@ -45,13 +45,13 @@ public class ExampleWithConstructor public int Sec { get; set; } public int? SecNull { get; set; } - public ExampleWithConstructor(DateTime t, DayOfWeek? dn, DayOfWeek d, int s, int? sn) + public ExampleWithConstructor(DateTime Time, DayOfWeek? DOWNull, DayOfWeek DOW, int Sec, int? SecNull) { - Time = t; - DOWNull = dn; - DOW = d; - Sec = s; - SecNull = sn; + this.Time = Time; + this.DOWNull = DOWNull; + this.DOW = DOW; + this.Sec = Sec; + this.SecNull = SecNull; } } From 6e8495d5852a535f7b7d036002415800ec8c1470 Mon Sep 17 00:00:00 2001 From: Jonas Daniels Date: Tue, 7 Dec 2021 13:00:01 +0100 Subject: [PATCH 5/5] bind parameters sequentially for legacy --- .../Parser/ExpressionParser.cs | 21 +++++++++++++------ .../QueryableTests.Select.cs | 12 +++++------ 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs index 71141b2a..7b78bf50 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs @@ -1471,16 +1471,25 @@ private Expression CreateNewExpression(List properties, List ctorParameters + .Any(cp => cp.Name == p.Name && (cp.ParameterType == p.Type || p.Type == Nullable.GetUnderlyingType(cp.ParameterType)))); var expressionsPromoted = new List(); // Loop all expressions and promote if needed for (int i = 0; i < ctorParameters.Length; i++) { - Type propertyType = ctorParameters[i].ParameterType; - string cParameterName = ctorParameters[i].Name; - var propertyAndIndex = properties.Select((p, index) => new { p, index }) - .First(p => p.p.Name == cParameterName && (p.p.Type == propertyType || p.p.Type == Nullable.GetUnderlyingType(propertyType))); - // Promote from Type to Nullable Type if needed - expressionsPromoted.Add(_parsingConfig.ExpressionPromoter.Promote(expressions[propertyAndIndex.index], propertyType, true, true)); + if (bindParametersSequentially) + { + expressionsPromoted.Add(_parsingConfig.ExpressionPromoter.Promote(expressions[i], propertyTypes[i], true, true)); + } + else + { + Type propertyType = ctorParameters[i].ParameterType; + string cParameterName = ctorParameters[i].Name; + var propertyAndIndex = properties.Select((p, index) => new { p, index }) + .First(p => p.p.Name == cParameterName && (p.p.Type == propertyType || p.p.Type == Nullable.GetUnderlyingType(propertyType))); + // Promote from Type to Nullable Type if needed + expressionsPromoted.Add(_parsingConfig.ExpressionPromoter.Promote(expressions[propertyAndIndex.index], propertyType, true, true)); + } } return Expression.New(ctor, expressionsPromoted, (IEnumerable)propertyInfos); diff --git a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Select.cs b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Select.cs index 9e8ba954..a0873b4a 100644 --- a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Select.cs +++ b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Select.cs @@ -45,13 +45,13 @@ public class ExampleWithConstructor public int Sec { get; set; } public int? SecNull { get; set; } - public ExampleWithConstructor(DateTime Time, DayOfWeek? DOWNull, DayOfWeek DOW, int Sec, int? SecNull) + public ExampleWithConstructor(DateTime t, DayOfWeek? dn, DayOfWeek d, int s, int? sn) { - this.Time = Time; - this.DOWNull = DOWNull; - this.DOW = DOW; - this.Sec = Sec; - this.SecNull = SecNull; + Time = t; + DOWNull = dn; + DOW = d; + Sec = s; + SecNull = sn; } }