diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs index dcf6a329..4a6319aa 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs @@ -1678,14 +1678,70 @@ private Expression CreateNewExpression(List properties, List(new ParsingConfig(), false, "new[]{1,2,3}.Any(z => z > 0)"); } + // https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/701 + [Fact] + public void DynamicExpressionParser_ParseLambda_NestedObjectInitialization() + { + // Arrange + var srcType = typeof(CustomerForNestedNewTest); + + // Act + var lambda = DynamicExpressionParser.ParseLambda(ParsingConfig.DefaultEFCore21, srcType, srcType, "new (new (3 as Id) as CurrentDepartment)"); + var @delegate = lambda.Compile(); + var result = (CustomerForNestedNewTest)@delegate.DynamicInvoke(new CustomerForNestedNewTest())!; + + // Assert + result.Should().NotBeNull(); + result.CurrentDepartment.Should().NotBeNull(); + result.CurrentDepartment!.Id.Should().Be(3); + } + + // https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/701 + [Fact] + public void DynamicExpressionParser_ParseLambda_NestedObjectInitialization_ThreeLevelsDeep() + { + // Arrange — exercises the recursive TryRebuildMemberInitExpression path. + // The parser propagates _resultType (CustomerForNestedNewTest) into all nested new + // expressions. The middle "new (new (3 as Id) as Sub)" therefore builds a + // MIE{ Sub = MIE{Id=3} }. When the outer new binds that to its own + // "Sub" property (type DepartmentForNestedNewTest), TryRebuildMemberInitExpression is + // called and encounters the inner MIE{Id=3} binding — a MemberInitExpression + // itself — which triggers the recursive call to rebuild it for SubDepartmentForNestedNewTest. + var srcType = typeof(CustomerForNestedNewTest); + + // Act + var lambda = DynamicExpressionParser.ParseLambda(ParsingConfig.DefaultEFCore21, srcType, srcType, + "new (new (new (3 as Id) as Sub) as Sub)"); + var @delegate = lambda.Compile(); + var result = (CustomerForNestedNewTest)@delegate.DynamicInvoke(new CustomerForNestedNewTest())!; + + // Assert + result.Should().NotBeNull(); + result.Sub.Should().NotBeNull(); + result.Sub!.Sub.Should().NotBeNull(); + result.Sub.Sub!.Id.Should().Be(3); + } + + public class CustomerForNestedNewTest + { + public int Id { get; set; } + public DepartmentForNestedNewTest? CurrentDepartment { get; set; } + public DepartmentForNestedNewTest? Sub { get; set; } + } + + public class DepartmentForNestedNewTest + { + public int Id { get; set; } + public SubDepartmentForNestedNewTest? Sub { get; set; } + } + + public class SubDepartmentForNestedNewTest + { + public int Id { get; set; } + } + public class DefaultDynamicLinqCustomTypeProviderForGenericExtensionMethod : DefaultDynamicLinqCustomTypeProvider { public DefaultDynamicLinqCustomTypeProviderForGenericExtensionMethod() : base(ParsingConfig.Default)