Skip to content

Commit 73d04db

Browse files
authored
bind expressions to correct constructor parameter (#557)
* bind expressions to correct constructor parameter * dynamic type test * linedata * fix Select_Dynamic_IntoTypeWithNullableProperties2 test * bind parameters sequentially for legacy
1 parent 6eee13a commit 73d04db

File tree

2 files changed

+47
-11
lines changed

2 files changed

+47
-11
lines changed

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

+24-10
Original file line numberDiff line numberDiff line change
@@ -1351,20 +1351,34 @@ private Expression CreateNewExpression(List<DynamicProperty> properties, List<Ex
13511351

13521352
Type[] propertyTypes = propertyInfos.Select(p => p.PropertyType).ToArray();
13531353
ConstructorInfo ctor = type.GetConstructor(propertyTypes);
1354-
if (ctor != null && ctor.GetParameters().Length == expressions.Count)
1354+
if (ctor != null)
13551355
{
1356-
var expressionsPromoted = new List<Expression>();
1357-
1358-
// Loop all expressions and promote if needed
1359-
for (int i = 0; i < propertyTypes.Length; i++)
1356+
var ctorParameters = ctor.GetParameters();
1357+
if (ctorParameters.Length == expressions.Count)
13601358
{
1361-
Type propertyType = propertyTypes[i];
1359+
bool bindParametersSequentially = !properties.All(p => ctorParameters
1360+
.Any(cp => cp.Name == p.Name && (cp.ParameterType == p.Type || p.Type == Nullable.GetUnderlyingType(cp.ParameterType))));
1361+
var expressionsPromoted = new List<Expression>();
1362+
// Loop all expressions and promote if needed
1363+
for (int i = 0; i < ctorParameters.Length; i++)
1364+
{
1365+
if (bindParametersSequentially)
1366+
{
1367+
expressionsPromoted.Add(_parsingConfig.ExpressionPromoter.Promote(expressions[i], propertyTypes[i], true, true));
1368+
}
1369+
else
1370+
{
1371+
Type propertyType = ctorParameters[i].ParameterType;
1372+
string cParameterName = ctorParameters[i].Name;
1373+
var propertyAndIndex = properties.Select((p, index) => new { p, index })
1374+
.First(p => p.p.Name == cParameterName && (p.p.Type == propertyType || p.p.Type == Nullable.GetUnderlyingType(propertyType)));
1375+
// Promote from Type to Nullable Type if needed
1376+
expressionsPromoted.Add(_parsingConfig.ExpressionPromoter.Promote(expressions[propertyAndIndex.index], propertyType, true, true));
1377+
}
1378+
}
13621379

1363-
// Promote from Type to Nullable Type if needed
1364-
expressionsPromoted.Add(_parsingConfig.ExpressionPromoter.Promote(expressions[i], propertyType, true, true));
1380+
return Expression.New(ctor, expressionsPromoted, (IEnumerable<MemberInfo>)propertyInfos);
13651381
}
1366-
1367-
return Expression.New(ctor, expressionsPromoted, (IEnumerable<MemberInfo>)propertyInfos);
13681382
}
13691383

13701384
MemberBinding[] bindings = new MemberBinding[properties.Count];

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

+23-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Linq.Dynamic.Core.Parser;
1+
using System.Collections.Generic;
2+
using System.Linq.Dynamic.Core.Parser;
23
using System.Linq.Expressions;
34
using FluentAssertions;
45
using Xunit;
@@ -97,5 +98,26 @@ public void ParseTypeAccess_Via_Constructor_String_And_UriKind_To_Uri()
9798
// Assert
9899
expression.ToString().Should().Be("new Uri(\"https://www.example.com/\", Absolute)");
99100
}
101+
102+
[Theory]
103+
[InlineData("new(1 as a, 2 as b)", "new*(a = 1, b = 2)")]
104+
[InlineData("new(2 as b, 1 as a)", "new*(a = 1, b = 2)")]
105+
public void ParseTypeAccess_Via_Constructor_DynamicType_To_String(string newExpression, string newExpression2)
106+
{
107+
// Arrange
108+
var parameter = Expression.Parameter(typeof(int));
109+
var parameter2 = Expression.Parameter(typeof(int));
110+
var returnType = DynamicClassFactory.CreateType(new List<DynamicProperty> {
111+
new DynamicProperty("a", typeof(int)),
112+
new DynamicProperty("b", typeof(int))
113+
});
114+
115+
// Act
116+
var parser = new ExpressionParser(new[] { parameter, parameter2 }, newExpression, new object[] { }, ParsingConfig.Default);
117+
118+
var expression = parser.Parse(returnType);
119+
// Assert
120+
expression.ToString().Should().Match(newExpression2);
121+
}
100122
}
101123
}

0 commit comments

Comments
 (0)