Skip to content

Commit c3e802c

Browse files
committed
Fixed SelectMany over an Array (#18)
1 parent 5aeb1dc commit c3e802c

File tree

2 files changed

+95
-36
lines changed

2 files changed

+95
-36
lines changed

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

+9-1
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,15 @@ private static IQueryable SelectManyInternal(IQueryable source, Type resultType,
202202
//http://stackoverflow.com/a/3001674/2465182
203203

204204
// if resultType is not specified, create one based on the lambda.Body.Type
205-
resultType = resultType ?? lambda.Body.Type.GetTypeInfo().GetGenericTypeArguments()[0];
205+
if (resultType == null)
206+
{
207+
// SelectMany assumes that lambda.Body.Type is a generic type and throws an exception on
208+
// lambda.Body.Type.GetGenericArguments()[0] when used over an array as GetGenericArguments() returns an empty array.
209+
if (lambda.Body.Type.IsArray)
210+
resultType = lambda.Body.Type.GetElementType();
211+
else
212+
resultType = lambda.Body.Type.GetGenericArguments()[0];
213+
}
206214

207215
//we have to adjust to lambda to return an IEnumerable<T> instead of whatever the actual property is.
208216
Type enumerableType = typeof(IEnumerable<>).MakeGenericType(resultType);

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

+86-35
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,59 @@ public void OrderBy_Exceptions()
117117
Assert.Throws<ArgumentException>(() => qry.OrderBy(" "));
118118
}
119119

120+
/// <summary>
121+
/// https://github.com/NArnott/System.Linq.Dynamic/issues/42 and https://github.com/StefH/System.Linq.Dynamic.Core/issues/18
122+
/// </summary>
123+
[Fact]
124+
public void SelectMany_OverArray()
125+
{
126+
var testList = new[]
127+
{
128+
new[] { 1 },
129+
new[] { 1, 2},
130+
new[] { 1, 2, 3},
131+
new[] { 1, 2, 3, 4},
132+
new[] { 1, 2, 3, 4, 5}
133+
};
134+
135+
var expectedResult = testList.SelectMany(it => it).ToList();
136+
var result = testList.AsQueryable().SelectMany("it").ToDynamicList<int>();
137+
138+
Assert.Equal(expectedResult, result);
139+
}
140+
141+
[Fact]
142+
public void SelectMany_OverArray_TResult()
143+
{
144+
var testList = new[]
145+
{
146+
new[] { new Permission { Name = "p-Admin" } },
147+
new[] { new Permission { Name = "p-Admin" }, new Permission { Name = "p-User" } },
148+
new[] { new Permission { Name = "p-x" }, new Permission { Name = "p-y" } }
149+
};
150+
151+
var expectedResult = testList.SelectMany(it => it).ToList();
152+
var result = testList.AsQueryable().SelectMany<Permission>("it").ToList();
153+
154+
Assert.Equal(expectedResult, result);
155+
}
156+
157+
[Fact]
158+
public void SelectMany_OverArray_IntoType()
159+
{
160+
var testList = new[]
161+
{
162+
new[] { new Permission { Name = "p-Admin" } },
163+
new[] { new Permission { Name = "p-Admin" }, new Permission { Name = "p-User" } },
164+
new[] { new Permission { Name = "p-x" }, new Permission { Name = "p-y" } }
165+
};
166+
167+
var expectedResult = testList.SelectMany(it => it).ToList();
168+
var result = testList.AsQueryable().SelectMany(typeof(Permission), "it").ToDynamicList<Permission>();
169+
170+
Assert.Equal(expectedResult, result);
171+
}
172+
120173
[Fact]
121174
public void SelectMany()
122175
{
@@ -156,8 +209,7 @@ public void SelectMany_TResult()
156209
new Role
157210
{
158211
Name = "Admin",
159-
Permissions =
160-
new List<Permission> {new Permission {Name = "p-Admin"}, new Permission {Name = "p-User"}}
212+
Permissions = new List<Permission> {new Permission {Name = "p-Admin"}, new Permission {Name = "p-User"}}
161213
}
162214
};
163215
users[1].Roles = new List<Role>
@@ -176,7 +228,7 @@ public void SelectMany_TResult()
176228
}
177229

178230
[Fact]
179-
public void SelectMany_Intotype()
231+
public void SelectMany_IntoType()
180232
{
181233
// Act
182234
var users = User.GenerateSampleModels(2);
@@ -185,8 +237,7 @@ public void SelectMany_Intotype()
185237
new Role
186238
{
187239
Name = "Admin",
188-
Permissions =
189-
new List<Permission> {new Permission {Name = "p-Admin"}, new Permission {Name = "p-User"}}
240+
Permissions = new List<Permission> {new Permission {Name = "p-Admin"}, new Permission {Name = "p-User"}}
190241
}
191242
};
192243
users[1].Roles = new List<Role>
@@ -198,7 +249,7 @@ public void SelectMany_Intotype()
198249

199250
// Assign
200251
var queryNormal = query.SelectMany(u => u.Roles.SelectMany(r => r.Permissions)).ToList();
201-
var queryDynamic = query.SelectMany(typeof (Permission), "Roles.SelectMany(Permissions)").ToDynamicList();
252+
var queryDynamic = query.SelectMany(typeof(Permission), "Roles.SelectMany(Permissions)").ToDynamicList();
202253

203254
// Assert
204255
Assert.Equal(queryNormal, queryDynamic);
@@ -208,37 +259,37 @@ public void SelectMany_Intotype()
208259
public void SelectMany_WithResultProjection()
209260
{
210261
//Arrange
211-
List<int> rangeOfInt = new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
212-
List<double> rangeOfDouble = new List<double> {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0};
262+
List<int> rangeOfInt = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
263+
List<double> rangeOfDouble = new List<double> { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0 };
213264
List<KeyValuePair<int, double>> range =
214265
rangeOfInt.SelectMany(e => rangeOfDouble, (x, y) => new KeyValuePair<int, double>(x, y)).ToList();
215266

216267
//Act
217268
IEnumerable rangeResult = rangeOfInt.AsQueryable()
218-
.SelectMany("@0", "new(x as _A, y as _B)", new object[] {rangeOfDouble})
269+
.SelectMany("@0", "new(x as _A, y as _B)", new object[] { rangeOfDouble })
219270
.Select("it._A * it._B");
220271

221272
//Assert
222-
Assert.Equal(range.Select(t => t.Key*t.Value).ToArray(), rangeResult.Cast<double>().ToArray());
273+
Assert.Equal(range.Select(t => t.Key * t.Value).ToArray(), rangeResult.Cast<double>().ToArray());
223274
}
224275

225276
[Fact]
226277
public void SelectMany_WithResultProjection_CustomParameterNames()
227278
{
228279
//Arrange
229-
List<int> rangeOfInt = new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
230-
List<double> rangeOfDouble = new List<double> {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0};
280+
List<int> rangeOfInt = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
281+
List<double> rangeOfDouble = new List<double> { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0 };
231282
List<KeyValuePair<int, double>> range =
232283
rangeOfInt.SelectMany(e => rangeOfDouble, (x, y) => new KeyValuePair<int, double>(x, y)).ToList();
233284

234285
//Act
235286
IEnumerable rangeResult = rangeOfInt.AsQueryable()
236287
.SelectMany("@0", "new(VeryNiceName as _A, OtherName as _X)", "VeryNiceName", "OtherName",
237-
new object[] {rangeOfDouble})
288+
new object[] { rangeOfDouble })
238289
.Select("it._A * it._X");
239290

240291
//Assert
241-
Assert.Equal(range.Select(t => t.Key*t.Value).ToArray(), rangeResult.Cast<double>().ToArray());
292+
Assert.Equal(range.Select(t => t.Key * t.Value).ToArray(), rangeResult.Cast<double>().ToArray());
242293
}
243294

244295
[Fact]
@@ -280,7 +331,7 @@ public void Select_PropertyVisitor_QueryInterceptor()
280331
public void Select_TResult()
281332
{
282333
//Arrange
283-
List<int> range = new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
334+
List<int> range = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
284335
var testList = User.GenerateSampleModels(100);
285336
var qry = testList.AsQueryable();
286337

@@ -290,7 +341,7 @@ public void Select_TResult()
290341
var userProfiles = qry.Select<UserProfile>("Profile").ToList();
291342

292343
//Assert
293-
Assert.Equal(range.Select(x => x*x).ToList(), rangeResult);
344+
Assert.Equal(range.Select(x => x * x).ToList(), rangeResult);
294345
Assert.Equal(testList.Select(x => x.UserName).ToList(), userNames);
295346
Assert.Equal(testList.Select(x => x.Profile).ToList(), userProfiles);
296347
}
@@ -299,17 +350,17 @@ public void Select_TResult()
299350
public void Select_IntoType()
300351
{
301352
//Arrange
302-
List<int> range = new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
353+
List<int> range = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
303354
var testList = User.GenerateSampleModels(10);
304355
var qry = testList.AsQueryable();
305356

306357
//Act
307-
IEnumerable rangeResult = range.AsQueryable().Select(typeof (int), "it * it");
308-
var userNames = qry.Select(typeof (string), "UserName");
309-
var userProfiles = qry.Select(typeof (UserProfile), "Profile");
358+
IEnumerable rangeResult = range.AsQueryable().Select(typeof(int), "it * it");
359+
var userNames = qry.Select(typeof(string), "UserName");
360+
var userProfiles = qry.Select(typeof(UserProfile), "Profile");
310361

311362
//Assert
312-
Assert.Equal(range.Select(x => x*x).Cast<object>().ToList(), rangeResult.ToDynamicList());
363+
Assert.Equal(range.Select(x => x * x).Cast<object>().ToList(), rangeResult.ToDynamicList());
313364
Assert.Equal(testList.Select(x => x.UserName).Cast<object>().ToList(), userNames.ToDynamicList());
314365
Assert.Equal(testList.Select(x => x.Profile).Cast<object>().ToList(), userProfiles.ToDynamicList());
315366
}
@@ -318,7 +369,7 @@ public void Select_IntoType()
318369
public void Select()
319370
{
320371
//Arrange
321-
List<int> range = new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
372+
List<int> range = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
322373
var testList = User.GenerateSampleModels(100);
323374
var qry = testList.AsQueryable();
324375

@@ -329,7 +380,7 @@ public void Select()
329380
var userRoles = qry.Select("new (UserName, Roles.Select(Id) AS RoleIds)");
330381

331382
//Assert
332-
Assert.Equal(range.Select(x => x*x).ToArray(), rangeResult.Cast<int>().ToArray());
383+
Assert.Equal(range.Select(x => x * x).ToArray(), rangeResult.Cast<int>().ToArray());
333384

334385
#if NET35 || DNXCORE50 || DOTNET5_4 || DOTNET5_1 || UAP10_0
335386
Assert.Equal(testList.Select(x => x.UserName).ToArray(), userNames.AsEnumerable().Cast<string>().ToArray());
@@ -396,12 +447,12 @@ public void GroupBy_Exceptions()
396447
Assert.Throws<ParseException>(() => qry.GroupBy("new (Id, UserName"));
397448
Assert.Throws<ParseException>(() => qry.GroupBy("new (Id, UserName, Bad)"));
398449

399-
Assert.Throws<ArgumentNullException>(() => DynamicQueryable.GroupBy((IQueryable<string>) null, "Id"));
450+
Assert.Throws<ArgumentNullException>(() => DynamicQueryable.GroupBy((IQueryable<string>)null, "Id"));
400451
Assert.Throws<ArgumentNullException>(() => qry.GroupBy(null));
401452
Assert.Throws<ArgumentException>(() => qry.GroupBy(""));
402453
Assert.Throws<ArgumentException>(() => qry.GroupBy(" "));
403454

404-
Assert.Throws<ArgumentNullException>(() => qry.GroupBy("Id", (string) null));
455+
Assert.Throws<ArgumentNullException>(() => qry.GroupBy("Id", (string)null));
405456
Assert.Throws<ArgumentException>(() => qry.GroupBy("Id", ""));
406457
Assert.Throws<ArgumentException>(() => qry.GroupBy("Id", " "));
407458
}
@@ -463,17 +514,17 @@ private class Pet
463514
public void Join()
464515
{
465516
//Arrange
466-
Person magnus = new Person {Name = "Hedlund, Magnus"};
467-
Person terry = new Person {Name = "Adams, Terry"};
468-
Person charlotte = new Person {Name = "Weiss, Charlotte"};
517+
Person magnus = new Person { Name = "Hedlund, Magnus" };
518+
Person terry = new Person { Name = "Adams, Terry" };
519+
Person charlotte = new Person { Name = "Weiss, Charlotte" };
469520

470-
Pet barley = new Pet {Name = "Barley", Owner = terry};
471-
Pet boots = new Pet {Name = "Boots", Owner = terry};
472-
Pet whiskers = new Pet {Name = "Whiskers", Owner = charlotte};
473-
Pet daisy = new Pet {Name = "Daisy", Owner = magnus};
521+
Pet barley = new Pet { Name = "Barley", Owner = terry };
522+
Pet boots = new Pet { Name = "Boots", Owner = terry };
523+
Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte };
524+
Pet daisy = new Pet { Name = "Daisy", Owner = magnus };
474525

475-
List<Person> people = new List<Person> {magnus, terry, charlotte};
476-
List<Pet> pets = new List<Pet> {barley, boots, whiskers, daisy};
526+
List<Person> people = new List<Person> { magnus, terry, charlotte };
527+
List<Pet> pets = new List<Pet> { barley, boots, whiskers, daisy };
477528

478529

479530
//Act
@@ -482,7 +533,7 @@ public void Join()
482533
person => person,
483534
pet => pet.Owner,
484535
(person, pet) =>
485-
new {OwnerName = person.Name, Pet = pet.Name});
536+
new { OwnerName = person.Name, Pet = pet.Name });
486537

487538
var dynamicQuery = people.AsQueryable().Join(
488539
pets,

0 commit comments

Comments
 (0)