Skip to content

Commit 02fd83b

Browse files
authored
Refactored Parser (#127)
* refactored * Fixed issue #129
1 parent bd69f2d commit 02fd83b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+2182
-1655
lines changed

src-console/ConsoleAppEF1.1/Program.cs

+8
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@ static void Main(string[] args)
1111
{
1212
using (var db = new MyDbContext())
1313
{
14+
var all = new
15+
{
16+
test1 = new List<int> { 1, 2, 3 }.ToDynamicList(typeof(int)),
17+
test2 = new List<dynamic> { 4, 5, 6 }.ToDynamicList(typeof(int)),
18+
test3 = new List<object> { 7, 8, 9 }.ToDynamicList(typeof(int))
19+
};
20+
Console.WriteLine("all {0}", JsonConvert.SerializeObject(all, Formatting.Indented));
21+
1422
var persons = new List<Person>
1523
{
1624
new Person { Name = "a", Age = 18, Address = new Address { Street = "s1" } },

src-console/ConsoleAppEF2.0/Program.cs

+15-6
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,16 @@ public HashSet<Type> GetCustomTypes()
2727

2828
static void Main(string[] args)
2929
{
30-
GlobalConfig.CustomTypeProvider = new C();
30+
var all = new
31+
{
32+
test1 = new List<int> { 1, 2, 3 }.ToDynamicList(typeof(int)),
33+
test2 = new List<dynamic> { 4, 5, 6 }.ToDynamicList(typeof(int)),
34+
test3 = new List<object> { 7, 8, 9 }.ToDynamicList(typeof(int))
35+
};
36+
Console.WriteLine("all {0}", JsonConvert.SerializeObject(all, Formatting.Indented));
37+
38+
var config = new ParsingConfig();
39+
config.CustomTypeProvider = new C();
3140

3241
var context = new TestContext();
3342

@@ -42,7 +51,7 @@ static void Main(string[] args)
4251
context.SaveChanges();
4352
}
4453

45-
var carFirstOrDefault = context.Cars.Where("Brand == \"Ford\"");
54+
var carFirstOrDefault = context.Cars.Where(config, "Brand == \"Ford\"");
4655
Console.WriteLine("carFirstOrDefault {0}", JsonConvert.SerializeObject(carFirstOrDefault, Formatting.Indented));
4756

4857
var carsLike1 =
@@ -54,16 +63,16 @@ where EF.Functions.Like(c.Brand, "%a%")
5463
var cars2Like = context.Cars.Where(c => EF.Functions.Like(c.Brand, "%a%"));
5564
Console.WriteLine("cars2Like {0}", JsonConvert.SerializeObject(cars2Like, Formatting.Indented));
5665

57-
var dynamicCarsLike1 = context.Cars.Where("TestContext.Like(Brand, \"%a%\")");
66+
var dynamicCarsLike1 = context.Cars.Where(config, "TestContext.Like(Brand, \"%a%\")");
5867
Console.WriteLine("dynamicCarsLike1 {0}", JsonConvert.SerializeObject(dynamicCarsLike1, Formatting.Indented));
5968

60-
var dynamicCarsLike2 = context.Cars.Where("TestContext.Like(Brand, \"%d%\")");
69+
var dynamicCarsLike2 = context.Cars.Where(config, "TestContext.Like(Brand, \"%d%\")");
6170
Console.WriteLine("dynamicCarsLike2 {0}", JsonConvert.SerializeObject(dynamicCarsLike2, Formatting.Indented));
6271

63-
var dynamicFunctionsLike1 = context.Cars.Where("DynamicFunctions.Like(Brand, \"%a%\")");
72+
var dynamicFunctionsLike1 = context.Cars.Where(config, "DynamicFunctions.Like(Brand, \"%a%\")");
6473
Console.WriteLine("dynamicFunctionsLike1 {0}", JsonConvert.SerializeObject(dynamicFunctionsLike1, Formatting.Indented));
6574

66-
var dynamicFunctionsLike2 = context.Cars.Where("DynamicFunctions.Like(Vin, \"%a.%b%\", \".\")");
75+
var dynamicFunctionsLike2 = context.Cars.Where(config, "DynamicFunctions.Like(Vin, \"%a.%b%\", \".\")");
6776
Console.WriteLine("dynamicFunctionsLike2 {0}", JsonConvert.SerializeObject(dynamicFunctionsLike2, Formatting.Indented));
6877
}
6978
}

src-console/ConsoleApp_net452_EF6/ConsoleApp_net452_EF6.csproj

+3
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@
6262
<Reference Include="Linq.Expression.Optimizer, Version=1.0.6.0, Culture=neutral, PublicKeyToken=34b6af2337893e15, processorArchitecture=MSIL">
6363
<HintPath>..\..\packages\Linq.Expression.Optimizer.1.0.9\lib\net45\Linq.Expression.Optimizer.dll</HintPath>
6464
</Reference>
65+
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
66+
<HintPath>..\..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
67+
</Reference>
6568
<Reference Include="System" />
6669
<Reference Include="System.ComponentModel.DataAnnotations" />
6770
<Reference Include="System.Core" />

src-console/ConsoleApp_net452_EF6/Program.cs

+10
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,24 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Linq;
34
using ConsoleApp_net452_EF6.Entities;
45
using System.Linq.Dynamic.Core;
6+
using Newtonsoft.Json;
57

68
namespace ConsoleApp_net452_EF6
79
{
810
class Program
911
{
1012
static void Main(string[] args)
1113
{
14+
var all = new
15+
{
16+
test1 = new List<int> { 1, 2, 3 }.ToDynamicList(typeof(int)),
17+
test2 = new List<dynamic> { 4, 5, 6 }.ToDynamicList(typeof(int)),
18+
test3 = new List<object> { 7, 8, 9 }.ToDynamicList(typeof(int))
19+
};
20+
21+
Console.WriteLine("all {0}", JsonConvert.SerializeObject(all, Formatting.Indented));
1222
using (var context = new KendoGridDbContext())
1323
{
1424
string search = "2";

src-console/ConsoleApp_net452_EF6/packages.config

+1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@
33
<package id="EntityFramework" version="6.2.0" targetFramework="net452" />
44
<package id="FSharp.Core" version="4.2.3" targetFramework="net452" />
55
<package id="Linq.Expression.Optimizer" version="1.0.9" targetFramework="net452" />
6+
<package id="Newtonsoft.Json" version="10.0.3" targetFramework="net452" />
67
</packages>

src/EntityFramework.DynamicLinq/EntityFramework.DynamicLinq.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<PropertyGroup>
33
<Description>Dynamic Linq extensions for EntityFramework which adds Async support</Description>
44
<AssemblyTitle>EntityFramework.DynamicLinq</AssemblyTitle>
5-
<VersionPrefix>1.0.4.7</VersionPrefix>
5+
<VersionPrefix>1.0.8.0</VersionPrefix>
66
<Authors>Stef Heyenrath</Authors>
77
<TargetFrameworks>net45;net46</TargetFrameworks>
88
<DefineConstants>EF</DefineConstants>

src/Microsoft.EntityFrameworkCore.DynamicLinq/Microsoft.EntityFrameworkCore.DynamicLinq.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<PropertyGroup>
33
<Description>Dynamic Linq extensions for Microsoft.EntityFrameworkCore which adds Async support</Description>
44
<AssemblyTitle>Microsoft.EntityFrameworkCore.DynamicLinq</AssemblyTitle>
5-
<VersionPrefix>1.0.4.8</VersionPrefix>
5+
<VersionPrefix>1.0.8.0</VersionPrefix>
66
<Authors>Stef Heyenrath</Authors>
77
<TargetFrameworks>net451;net46;netstandard1.3;netstandard2.0;uap10.0</TargetFrameworks>
88
<DefineConstants>$(DefineConstants);EFCORE</DefineConstants>

src/System.Linq.Dynamic.Core/CustomTypeProviders/DefaultDynamicLinqCustomTypeProvider.cs

+3-1
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,14 @@ public class DefaultDynamicLinqCustomTypeProvider : AbstractDynamicLinqCustomTyp
2121
public virtual HashSet<Type> GetCustomTypes()
2222
{
2323
if (_customTypes != null)
24+
{
2425
return _customTypes;
26+
}
2527

2628
IEnumerable<Assembly> assemblies = _assemblyHelper.GetAssemblies();
2729
_customTypes = new HashSet<Type>(FindTypesMarkedWithDynamicLinqTypeAttribute(assemblies));
2830
return _customTypes;
2931
}
3032
}
3133
}
32-
#endif
34+
#endif

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

+4-4
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,11 @@ public static dynamic[] ToDynamicArray([NotNull] this IEnumerable source, [NotNu
6565
Check.NotNull(source, nameof(source));
6666
Check.NotNull(type, nameof(type));
6767

68-
object result = ToDynamicArrayGenericMethod.MakeGenericMethod(type).Invoke(source, new object[] { source });
68+
IEnumerable result = (IEnumerable)ToDynamicArrayGenericMethod.MakeGenericMethod(type).Invoke(source, new object[] { source });
6969
#if NET35
70-
return (object[])result;
70+
return CastToArray<object>(result);
7171
#else
72-
return (dynamic[])result;
72+
return CastToArray<dynamic>(result);
7373
#endif
7474
}
7575

@@ -132,4 +132,4 @@ internal static List<T> CastToList<T>(IEnumerable source)
132132
return source.Cast<T>().ToList();
133133
}
134134
}
135-
}
135+
}

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

+34-26
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using JetBrains.Annotations;
1+
using System.Linq.Dynamic.Core.Parser;
2+
using JetBrains.Annotations;
23
using System.Linq.Dynamic.Core.Validation;
34
using System.Linq.Expressions;
45

@@ -14,43 +15,41 @@ public static class DynamicExpressionParser
1415
/// </summary>
1516
/// <param name="resultType">Type of the result. If not specified, it will be generated dynamically.</param>
1617
/// <param name="expression">The expression.</param>
18+
/// <param name="parsingConfig">The Configuration for the parsing.</param>
1719
/// <param name="values">An object array that contains zero or more objects which are used as replacement values.</param>
1820
/// <returns>The generated <see cref="LambdaExpression"/></returns>
1921
[PublicAPI]
20-
public static LambdaExpression ParseLambda([CanBeNull] Type resultType, string expression, params object[] values)
22+
public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, [CanBeNull] Type resultType, [NotNull] string expression, params object[] values)
2123
{
22-
return ParseLambda(true, resultType, expression, values);
24+
return ParseLambda(parsingConfig, true, resultType, expression, values);
2325
}
2426

2527
/// <summary>
26-
/// Parses an expression into a LambdaExpression.
28+
/// Parses an expression into a LambdaExpression. (Also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.)
2729
/// </summary>
28-
/// <param name="createParameterCtor">if set to <c>true</c> then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.</param>
2930
/// <param name="resultType">Type of the result. If not specified, it will be generated dynamically.</param>
3031
/// <param name="expression">The expression.</param>
3132
/// <param name="values">An object array that contains zero or more objects which are used as replacement values.</param>
3233
/// <returns>The generated <see cref="LambdaExpression"/></returns>
3334
[PublicAPI]
34-
public static LambdaExpression ParseLambda(bool createParameterCtor, [CanBeNull] Type resultType, string expression, params object[] values)
35+
public static LambdaExpression ParseLambda([CanBeNull] Type resultType, [NotNull] string expression, params object[] values)
3536
{
3637
Check.NotEmpty(expression, nameof(expression));
3738

38-
var parser = new ExpressionParser(new ParameterExpression[0], expression, values, null);
39-
40-
return Expression.Lambda(parser.Parse(resultType, true));
39+
return ParseLambda(null, true, resultType, expression, values);
4140
}
4241

4342
/// <summary>
4443
/// Parses an expression into a LambdaExpression.
4544
/// </summary>
45+
/// <param name="parsingConfig">The Configuration for the parsing.</param>
4646
/// <param name="createParameterCtor">if set to <c>true</c> then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.</param>
4747
/// <param name="resultType">Type of the result. If not specified, it will be generated dynamically.</param>
4848
/// <param name="expression">The expression.</param>
49-
/// <param name="parsingConfig">The Configuration for the parsing.</param>
5049
/// <param name="values">An object array that contains zero or more objects which are used as replacement values.</param>
5150
/// <returns>The generated <see cref="LambdaExpression"/></returns>
5251
[PublicAPI]
53-
public static LambdaExpression ParseLambda(bool createParameterCtor, [CanBeNull] Type resultType, string expression, ParsingConfig parsingConfig, params object[] values)
52+
public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [CanBeNull] Type resultType, string expression, params object[] values)
5453
{
5554
Check.NotEmpty(expression, nameof(expression));
5655

@@ -83,7 +82,7 @@ public static LambdaExpression ParseLambda([NotNull] Type itType, [CanBeNull] Ty
8382
/// <param name="values">An object array that contains zero or more objects which are used as replacement values.</param>
8483
/// <returns>The generated <see cref="LambdaExpression"/></returns>
8584
[PublicAPI]
86-
public static LambdaExpression ParseLambda([NotNull] Type itType, [CanBeNull] Type resultType, string expression, ParsingConfig parsingConfig, params object[] values)
85+
public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, [NotNull] Type itType, [CanBeNull] Type resultType, string expression, params object[] values)
8786
{
8887
return ParseLambda(true, itType, resultType, expression, parsingConfig, values);
8988
}
@@ -109,20 +108,20 @@ public static LambdaExpression ParseLambda(bool createParameterCtor, [NotNull] T
109108
/// <summary>
110109
/// Parses an expression into a LambdaExpression.
111110
/// </summary>
111+
/// <param name="parsingConfig">The Configuration for the parsing.</param>
112112
/// <param name="createParameterCtor">if set to <c>true</c> then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.</param>
113113
/// <param name="itType">The main type from the dynamic class expression.</param>
114114
/// <param name="resultType">Type of the result. If not specified, it will be generated dynamically.</param>
115115
/// <param name="expression">The expression.</param>
116-
/// <param name="parsingConfig">The Configuration for the parsing.</param>
117116
/// <param name="values">An object array that contains zero or more objects which are used as replacement values.</param>
118117
/// <returns>The generated <see cref="LambdaExpression"/></returns>
119118
[PublicAPI]
120-
public static LambdaExpression ParseLambda(bool createParameterCtor, [NotNull] Type itType, [CanBeNull] Type resultType, string expression, ParsingConfig parsingConfig, params object[] values)
119+
public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] Type itType, [CanBeNull] Type resultType, string expression, params object[] values)
121120
{
122121
Check.NotNull(itType, nameof(itType));
123122
Check.NotEmpty(expression, nameof(expression));
124123

125-
return ParseLambda(createParameterCtor, new[] { Expression.Parameter(itType, "") }, resultType, expression, parsingConfig, values);
124+
return ParseLambda(parsingConfig, createParameterCtor, new[] { Expression.Parameter(itType, "") }, resultType, expression, values);
126125
}
127126

128127
/// <summary>
@@ -136,7 +135,22 @@ public static LambdaExpression ParseLambda(bool createParameterCtor, [NotNull] T
136135
[PublicAPI]
137136
public static LambdaExpression ParseLambda([NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, string expression, params object[] values)
138137
{
139-
return ParseLambda(true, parameters, resultType, expression, values);
138+
return ParseLambda(null, true, parameters, resultType, expression, values);
139+
}
140+
141+
/// <summary>
142+
/// Parses an expression into a LambdaExpression. (Also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.)
143+
/// </summary>
144+
/// <param name="parsingConfig">The Configuration for the parsing.</param>
145+
/// <param name="parameters">A array from ParameterExpressions.</param>
146+
/// <param name="resultType">Type of the result. If not specified, it will be generated dynamically.</param>
147+
/// <param name="expression">The expression.</param>
148+
/// <param name="values">An object array that contains zero or more objects which are used as replacement values.</param>
149+
/// <returns>The generated <see cref="LambdaExpression"/></returns>
150+
[PublicAPI]
151+
public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, [NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, string expression, params object[] values)
152+
{
153+
return ParseLambda(parsingConfig, true, parameters, resultType, expression, values);
140154
}
141155

142156
/// <summary>
@@ -149,29 +163,23 @@ public static LambdaExpression ParseLambda([NotNull] ParameterExpression[] param
149163
/// <param name="values">An object array that contains zero or more objects which are used as replacement values.</param>
150164
/// <returns>The generated <see cref="LambdaExpression"/></returns>
151165
[PublicAPI]
152-
public static LambdaExpression ParseLambda(bool createParameterCtor, [NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, string expression, params object[] values)
166+
public static LambdaExpression ParseLambda(bool createParameterCtor, [NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, [NotNull] string expression, params object[] values)
153167
{
154-
Check.NotNull(parameters, nameof(parameters));
155-
Check.Condition(parameters, p => p.Count(x => x == null) == 0, nameof(parameters));
156-
Check.NotEmpty(expression, nameof(expression));
157-
158-
var parser = new ExpressionParser(parameters, expression, values, null);
159-
160-
return Expression.Lambda(parser.Parse(resultType, createParameterCtor), parameters);
168+
return ParseLambda(null, createParameterCtor, parameters, resultType, expression, values);
161169
}
162170

163171
/// <summary>
164172
/// Parses an expression into a LambdaExpression.
165173
/// </summary>
174+
/// <param name="parsingConfig">The Configuration for the parsing.</param>
166175
/// <param name="createParameterCtor">if set to <c>true</c> then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.</param>
167176
/// <param name="parameters">A array from ParameterExpressions.</param>
168177
/// <param name="resultType">Type of the result. If not specified, it will be generated dynamically.</param>
169178
/// <param name="expression">The expression.</param>
170-
/// <param name="parsingConfig">The Configuration for the parsing.</param>
171179
/// <param name="values">An object array that contains zero or more objects which are used as replacement values.</param>
172180
/// <returns>The generated <see cref="LambdaExpression"/></returns>
173181
[PublicAPI]
174-
public static LambdaExpression ParseLambda(bool createParameterCtor, [NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, string expression, ParsingConfig parsingConfig, params object[] values)
182+
public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, [NotNull] string expression, params object[] values)
175183
{
176184
Check.NotNull(parameters, nameof(parameters));
177185
Check.Condition(parameters, p => p.Count(x => x == null) == 0, nameof(parameters));

0 commit comments

Comments
 (0)