Skip to content

Commit ed2ebb4

Browse files
CopilotStefH
andcommitted
Fix error when parsing nested object initialization (issue #701)
Agent-Logs-Url: https://github.com/zzzprojects/System.Linq.Dynamic.Core/sessions/4683789c-0227-43d7-9432-4863adea1d4c Co-authored-by: StefH <249938+StefH@users.noreply.github.com>
1 parent 15eebe9 commit ed2ebb4

File tree

2 files changed

+85
-3
lines changed

2 files changed

+85
-3
lines changed

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

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1678,14 +1678,67 @@ private Expression CreateNewExpression(List<DynamicProperty> properties, List<Ex
16781678
propertyOrFieldType = fieldInfo.FieldType;
16791679
}
16801680

1681-
// Call Promote and if that returns false, just try to convert the expression to the destination type using Expression.Convert
1682-
var promoted = _parsingConfig.ExpressionPromoter.Promote(expressions[i], propertyOrFieldType, true, true) ?? Expression.Convert(expressions[i], propertyOrFieldType);
1683-
memberBindings[i] = Expression.Bind(memberInfo, promoted);
1681+
// Call Promote and if that returns null, try to rebuild a nested MemberInitExpression for the target type,
1682+
// and if that also fails, try to convert the expression to the destination type using Expression.Convert.
1683+
var promoted = _parsingConfig.ExpressionPromoter.Promote(expressions[i], propertyOrFieldType, true, true);
1684+
if (promoted == null && expressions[i] is MemberInitExpression memberInitExpression)
1685+
{
1686+
promoted = TryRebuildMemberInitExpression(memberInitExpression, propertyOrFieldType);
1687+
}
1688+
memberBindings[i] = Expression.Bind(memberInfo, promoted ?? Expression.Convert(expressions[i], propertyOrFieldType));
16841689
}
16851690

16861691
return Expression.MemberInit(Expression.New(type), memberBindings);
16871692
}
16881693

1694+
private static Expression? TryRebuildMemberInitExpression(MemberInitExpression memberInitExpression, Type targetType)
1695+
{
1696+
var defaultConstructor = targetType.GetConstructor(Type.EmptyTypes);
1697+
if (defaultConstructor == null)
1698+
{
1699+
return null;
1700+
}
1701+
1702+
var newBindings = new MemberBinding[memberInitExpression.Bindings.Count];
1703+
for (var i = 0; i < memberInitExpression.Bindings.Count; i++)
1704+
{
1705+
if (memberInitExpression.Bindings[i] is not MemberAssignment assignment)
1706+
{
1707+
return null;
1708+
}
1709+
1710+
var memberName = assignment.Member.Name;
1711+
MemberInfo? targetMember = targetType.GetProperty(memberName) ?? (MemberInfo?)targetType.GetField(memberName);
1712+
if (targetMember == null)
1713+
{
1714+
return null;
1715+
}
1716+
1717+
var targetMemberType = targetMember is PropertyInfo targetPropertyInfo
1718+
? targetPropertyInfo.PropertyType
1719+
: ((FieldInfo)targetMember).FieldType;
1720+
1721+
var bindingExpression = assignment.Expression;
1722+
if (bindingExpression is MemberInitExpression nestedMemberInit && bindingExpression.Type != targetMemberType)
1723+
{
1724+
var rebuilt = TryRebuildMemberInitExpression(nestedMemberInit, targetMemberType);
1725+
if (rebuilt == null)
1726+
{
1727+
return null;
1728+
}
1729+
bindingExpression = rebuilt;
1730+
}
1731+
else if (bindingExpression.Type != targetMemberType)
1732+
{
1733+
bindingExpression = Expression.Convert(bindingExpression, targetMemberType);
1734+
}
1735+
1736+
newBindings[i] = Expression.Bind(targetMember, bindingExpression);
1737+
}
1738+
1739+
return Expression.MemberInit(Expression.New(targetType), newBindings);
1740+
}
1741+
16891742
private Expression ParseLambdaInvocation(LambdaExpression lambda)
16901743
{
16911744
int errorPos = _textParser.CurrentToken.Pos;

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2303,6 +2303,35 @@ public void DynamicExpressionParser_ParseLambda_LambdaParameter_SameNameAsDynami
23032303
DynamicExpressionParser.ParseLambda<bool>(new ParsingConfig(), false, "new[]{1,2,3}.Any(z => z > 0)");
23042304
}
23052305

2306+
// https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/701
2307+
[Fact]
2308+
public void DynamicExpressionParser_ParseLambda_NestedObjectInitialization()
2309+
{
2310+
// Arrange
2311+
var srcType = typeof(CustomerForNestedNewTest);
2312+
2313+
// Act
2314+
var lambda = DynamicExpressionParser.ParseLambda(ParsingConfig.DefaultEFCore21, srcType, srcType, "new (new (3 as Id) as CurrentDepartment)");
2315+
var @delegate = lambda.Compile();
2316+
var result = (CustomerForNestedNewTest)@delegate.DynamicInvoke(new CustomerForNestedNewTest())!;
2317+
2318+
// Assert
2319+
result.Should().NotBeNull();
2320+
result.CurrentDepartment.Should().NotBeNull();
2321+
result.CurrentDepartment!.Id.Should().Be(3);
2322+
}
2323+
2324+
public class CustomerForNestedNewTest
2325+
{
2326+
public int Id { get; set; }
2327+
public DepartmentForNestedNewTest? CurrentDepartment { get; set; }
2328+
}
2329+
2330+
public class DepartmentForNestedNewTest
2331+
{
2332+
public int Id { get; set; }
2333+
}
2334+
23062335
public class DefaultDynamicLinqCustomTypeProviderForGenericExtensionMethod : DefaultDynamicLinqCustomTypeProvider
23072336
{
23082337
public DefaultDynamicLinqCustomTypeProviderForGenericExtensionMethod() : base(ParsingConfig.Default)

0 commit comments

Comments
 (0)