Skip to content

Commit 9585b9f

Browse files
committed
Support of Initializing Named Types with new
1 parent 18bc30e commit 9585b9f

File tree

2 files changed

+78
-4
lines changed

2 files changed

+78
-4
lines changed

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

+23-3
Original file line numberDiff line numberDiff line change
@@ -1314,10 +1314,22 @@ Expression ParseNew()
13141314
if (_textParser.CurrentToken.Id == TokenId.Identifier)
13151315
{
13161316
var newTypeName = _textParser.CurrentToken.Text;
1317+
_textParser.NextToken();
1318+
1319+
while (_textParser.CurrentToken.Id == TokenId.Dot || _textParser.CurrentToken.Id == TokenId.Plus)
1320+
{
1321+
var sep = _textParser.CurrentToken.Text;
1322+
_textParser.NextToken();
1323+
if (_textParser.CurrentToken.Id != TokenId.Identifier)
1324+
throw ParseError(Res.IdentifierExpected);
1325+
newTypeName += sep + _textParser.CurrentToken.Text;
1326+
_textParser.NextToken();
1327+
}
1328+
13171329
newType = FindType(newTypeName);
13181330
if (newType == null)
13191331
throw ParseError(_textParser.CurrentToken.Pos, Res.TypeNotFound, newTypeName);
1320-
_textParser.NextToken();
1332+
13211333
if (_textParser.CurrentToken.Id != TokenId.OpenParen &&
13221334
_textParser.CurrentToken.Id != TokenId.OpenBracket &&
13231335
_textParser.CurrentToken.Id != TokenId.OpenCurlyParen)
@@ -1414,9 +1426,13 @@ private Expression CreateNewExpression(List<DynamicProperty> properties, List<Ex
14141426
#endif
14151427
type = typeof(DynamicClass);
14161428
Type typeForKeyValuePair = typeof(KeyValuePair<string, object>);
1429+
#if NET35 || NET40
1430+
ConstructorInfo constructorForKeyValuePair =
1431+
typeForKeyValuePair.GetConstructors().First();
1432+
#else
14171433
ConstructorInfo constructorForKeyValuePair =
14181434
typeForKeyValuePair.GetTypeInfo().DeclaredConstructors.First();
1419-
1435+
#endif
14201436
var arrayIndexParams = new List<Expression>();
14211437
for (int i = 0; i < expressions.Count; i++)
14221438
{
@@ -1433,7 +1449,11 @@ private Expression CreateNewExpression(List<DynamicProperty> properties, List<Ex
14331449
Expression.NewArrayInit(typeof(KeyValuePair<string, object>), arrayIndexParams);
14341450

14351451
// Get the "public DynamicClass(KeyValuePair<string, object>[] propertylist)" constructor
1452+
#if NET35 || NET40
1453+
ConstructorInfo constructor = type.GetConstructors().First();
1454+
#else
14361455
ConstructorInfo constructor = type.GetTypeInfo().DeclaredConstructors.First();
1456+
#endif
14371457
return Expression.New(constructor, newArrayExpression);
14381458
#if !UAP10_0
14391459
}
@@ -1446,7 +1466,7 @@ private Expression CreateNewExpression(List<DynamicProperty> properties, List<Ex
14461466

14471467
Type[] propertyTypes = type.GetProperties().Select(p => p.PropertyType).ToArray();
14481468
ConstructorInfo ctor = type.GetConstructor(propertyTypes);
1449-
if (ctor != null)
1469+
if (ctor != null && ctor.GetParameters().Length == expressions.Count)
14501470
return Expression.New(ctor, expressions);
14511471

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

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

+55-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
using NFluent;
22
using System.Collections.Generic;
3+
using System.Linq.Dynamic.Core.CustomTypeProviders;
34
using System.Linq.Dynamic.Core.Exceptions;
45
using System.Linq.Expressions;
6+
using System.Reflection;
57
using Xunit;
68
using User = System.Linq.Dynamic.Core.Tests.Helpers.Models.User;
79

@@ -23,6 +25,29 @@ private class ComplexParseLambda1Result
2325
public int TotalIncome;
2426
}
2527

28+
[DynamicLinqType]
29+
public class ComplexParseLambda3Result
30+
{
31+
public int? Age { get; set; }
32+
public int TotalIncome { get; set; }
33+
}
34+
35+
private class TestCustomTypeProvider : AbstractDynamicLinqCustomTypeProvider, IDynamicLinkCustomTypeProvider
36+
{
37+
private HashSet<Type> _customTypes;
38+
39+
public virtual HashSet<Type> GetCustomTypes()
40+
{
41+
if (_customTypes != null)
42+
return _customTypes;
43+
44+
_customTypes =
45+
new HashSet<Type>(
46+
FindTypesMarkedWithDynamicLinqTypeAttribute(new[] {this.GetType().GetTypeInfo().Assembly}));
47+
return _customTypes;
48+
}
49+
}
50+
2651
[Fact]
2752
public void ParseLambda_ToList()
2853
{
@@ -70,7 +95,6 @@ public void ParseLambda_Complex_1()
7095
Check.That(result.ToArray()[0]).Equals(expected[0]);
7196
}
7297

73-
7498
[Fact]
7599
public void ParseLambda_Complex_2()
76100
{
@@ -92,6 +116,36 @@ public void ParseLambda_Complex_2()
92116
Check.That(result.ToArray()[0]).Equals(expected[0]);
93117
}
94118

119+
[Fact]
120+
public void ParseLambda_Complex_3()
121+
{
122+
GlobalConfig.CustomTypeProvider = new TestCustomTypeProvider();
123+
124+
// Arrange
125+
var testList = User.GenerateSampleModels(51);
126+
var qry = testList.AsQueryable();
127+
128+
var externals = new Dictionary<string, object>
129+
{
130+
{ "Users", qry }
131+
};
132+
133+
// Act
134+
string query = "Users.GroupBy(x => new { x.Profile.Age }).OrderBy(gg => gg.Key.Age).Select(j => new System.Linq.Dynamic.Core.Tests.DynamicExpressionParserTests+ComplexParseLambda3Result{j.Key.Age, j.Sum(k => k.Income) As TotalIncome})";
135+
LambdaExpression expression = DynamicExpressionParser.ParseLambda(null, query, externals);
136+
Delegate del = expression.Compile();
137+
IEnumerable<dynamic> result = del.DynamicInvoke() as IEnumerable<dynamic>;
138+
139+
var expected = qry.GroupBy(x => new { x.Profile.Age }).OrderBy(gg => gg.Key.Age).Select(j => new ComplexParseLambda3Result { Age = j.Key.Age, TotalIncome = j.Sum(k => k.Income) }).Cast<dynamic>().ToArray();
140+
141+
// Assert
142+
Check.That(result).IsNotNull();
143+
Check.That(result).HasSize(expected.Length);
144+
Check.That(result.ToArray()[0]).Equals(expected[0]);
145+
146+
GlobalConfig.CustomTypeProvider = null;
147+
}
148+
95149
[Fact]
96150
public void ParseLambda_Select_1()
97151
{

0 commit comments

Comments
 (0)