diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs index 2f068add..7b78bf50 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs @@ -1466,20 +1466,34 @@ 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]; + bool bindParametersSequentially = !properties.All(p => 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++) + { + 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)); + } + } - // 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]; 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..c5bed90c 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,26 @@ 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(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 + 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 expression = parser.Parse(returnType); + // Assert + expression.ToString().Should().Match(newExpression2); + } } }