1
1
using System . Collections . Generic ;
2
+ using System . Diagnostics . CodeAnalysis ;
3
+ using System . Linq . Dynamic . Core . Validation ;
2
4
using System . Linq . Expressions ;
3
5
4
- namespace System . Linq . Dynamic . Core . Parser
6
+ namespace System . Linq . Dynamic . Core . Parser ;
7
+
8
+ internal class KeywordsHelper : IKeywordsHelper
5
9
{
6
- internal class KeywordsHelper : IKeywordsHelper
10
+ public const string KEYWORD_IT = "it" ;
11
+ public const string KEYWORD_PARENT = "parent" ;
12
+ public const string KEYWORD_ROOT = "root" ;
13
+
14
+ public const string SYMBOL_IT = "$" ;
15
+ public const string SYMBOL_PARENT = "^" ;
16
+ public const string SYMBOL_ROOT = "~" ;
17
+
18
+ public const string FUNCTION_IIF = "iif" ;
19
+ public const string FUNCTION_ISNULL = "isnull" ;
20
+ public const string FUNCTION_NEW = "new" ;
21
+ public const string FUNCTION_NULLPROPAGATION = "np" ;
22
+ public const string FUNCTION_IS = "is" ;
23
+ public const string FUNCTION_AS = "as" ;
24
+ public const string FUNCTION_CAST = "cast" ;
25
+
26
+ private readonly ParsingConfig _config ;
27
+
28
+ // Keywords are IgnoreCase
29
+ private readonly Dictionary < string , object > _keywordMapping = new ( StringComparer . OrdinalIgnoreCase )
7
30
{
8
- public const string SYMBOL_IT = "$" ;
9
- public const string SYMBOL_PARENT = "^" ;
10
- public const string SYMBOL_ROOT = "~" ;
11
-
12
- public const string KEYWORD_IT = "it" ;
13
- public const string KEYWORD_PARENT = "parent" ;
14
- public const string KEYWORD_ROOT = "root" ;
15
-
16
- public const string FUNCTION_IIF = "iif" ;
17
- public const string FUNCTION_ISNULL = "isnull" ;
18
- public const string FUNCTION_NEW = "new" ;
19
- public const string FUNCTION_NULLPROPAGATION = "np" ;
20
- public const string FUNCTION_IS = "is" ;
21
- public const string FUNCTION_AS = "as" ;
22
- public const string FUNCTION_CAST = "cast" ;
23
-
24
- private readonly IDictionary < string , object > _keywords = new Dictionary < string , object > ( StringComparer . OrdinalIgnoreCase )
25
- {
26
- { "true" , Expression . Constant ( true ) } ,
27
- { "false" , Expression . Constant ( false ) } ,
28
- { "null" , Expression . Constant ( null ) }
29
- } ;
31
+ { "true" , Expression . Constant ( true ) } ,
32
+ { "false" , Expression . Constant ( false ) } ,
33
+ { "null" , Expression . Constant ( null ) } ,
34
+
35
+ { SYMBOL_IT , SYMBOL_IT } ,
36
+ { SYMBOL_PARENT , SYMBOL_PARENT } ,
37
+ { SYMBOL_ROOT , SYMBOL_ROOT } ,
38
+
39
+ { FUNCTION_IIF , FUNCTION_IIF } ,
40
+ { FUNCTION_ISNULL , FUNCTION_ISNULL } ,
41
+ { FUNCTION_NEW , FUNCTION_NEW } ,
42
+ { FUNCTION_NULLPROPAGATION , FUNCTION_NULLPROPAGATION } ,
43
+ { FUNCTION_IS , FUNCTION_IS } ,
44
+ { FUNCTION_AS , FUNCTION_AS } ,
45
+ { FUNCTION_CAST , FUNCTION_CAST }
46
+ } ;
47
+
48
+ // PreDefined Types are not IgnoreCase
49
+ private static readonly Dictionary < string , object > _preDefinedTypeMapping = new ( ) ;
50
+
51
+ // Custom DefinedTypes are not IgnoreCase
52
+ private readonly Dictionary < string , object > _customTypeMapping = new ( ) ;
30
53
31
- public KeywordsHelper ( ParsingConfig config )
54
+ static KeywordsHelper ( )
55
+ {
56
+ foreach ( var type in PredefinedTypesHelper . PredefinedTypes . OrderBy ( kvp => kvp . Value ) . Select ( kvp => kvp . Key ) )
32
57
{
33
- if ( config . AreContextKeywordsEnabled )
34
- {
35
- _keywords . Add ( KEYWORD_IT , KEYWORD_IT ) ;
36
- _keywords . Add ( KEYWORD_PARENT , KEYWORD_PARENT ) ;
37
- _keywords . Add ( KEYWORD_ROOT , KEYWORD_ROOT ) ;
38
- }
58
+ _preDefinedTypeMapping [ type . FullName ! ] = type ;
59
+ _preDefinedTypeMapping [ type . Name ] = type ;
60
+ }
61
+ }
39
62
40
- _keywords . Add ( SYMBOL_IT , SYMBOL_IT ) ;
41
- _keywords . Add ( SYMBOL_PARENT , SYMBOL_PARENT ) ;
42
- _keywords . Add ( SYMBOL_ROOT , SYMBOL_ROOT ) ;
63
+ public KeywordsHelper ( ParsingConfig config )
64
+ {
65
+ _config = Check . NotNull ( config ) ;
43
66
44
- _keywords . Add ( FUNCTION_IIF , FUNCTION_IIF ) ;
45
- _keywords . Add ( FUNCTION_ISNULL , FUNCTION_ISNULL ) ;
46
- _keywords . Add ( FUNCTION_NEW , FUNCTION_NEW ) ;
47
- _keywords . Add ( FUNCTION_NULLPROPAGATION , FUNCTION_NULLPROPAGATION ) ;
48
- _keywords . Add ( FUNCTION_IS , FUNCTION_IS ) ;
49
- _keywords . Add ( FUNCTION_AS , FUNCTION_AS ) ;
50
- _keywords . Add ( FUNCTION_CAST , FUNCTION_CAST ) ;
67
+ if ( config . AreContextKeywordsEnabled )
68
+ {
69
+ _keywordMapping . Add ( KEYWORD_IT , KEYWORD_IT ) ;
70
+ _keywordMapping . Add ( KEYWORD_PARENT , KEYWORD_PARENT ) ;
71
+ _keywordMapping . Add ( KEYWORD_ROOT , KEYWORD_ROOT ) ;
72
+ }
51
73
52
- foreach ( Type type in PredefinedTypesHelper . PredefinedTypes . OrderBy ( kvp => kvp . Value ) . Select ( kvp => kvp . Key ) )
74
+ // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
75
+ if ( config . CustomTypeProvider != null )
76
+ {
77
+ foreach ( var type in config . CustomTypeProvider . GetCustomTypes ( ) )
53
78
{
54
- if ( ! string . IsNullOrEmpty ( type . FullName ) )
55
- {
56
- _keywords [ type . FullName ] = type ;
57
- }
58
- _keywords [ type . Name ] = type ;
79
+ _customTypeMapping [ type . FullName ! ] = type ;
80
+ _customTypeMapping [ type . Name ] = type ;
59
81
}
82
+ }
83
+ }
60
84
61
- foreach ( var pair in PredefinedTypesHelper . PredefinedTypesShorthands )
62
- {
63
- _keywords . Add ( pair . Key , pair . Value ) ;
64
- }
85
+ public bool TryGetValue ( string name , [ NotNullWhen ( true ) ] out object ? keyWordOrType )
86
+ {
87
+ // 1. Try to get as keyword
88
+ if ( _keywordMapping . TryGetValue ( name , out var keyWord ) )
89
+ {
90
+ keyWordOrType = keyWord ;
91
+ return true ;
92
+ }
65
93
66
- if ( config . SupportEnumerationsFromSystemNamespace )
67
- {
68
- foreach ( var pair in EnumerationsFromMscorlib . PredefinedEnumerationTypes )
69
- {
70
- _keywords . Add ( pair . Key , pair . Value ) ;
71
- }
72
- }
94
+ // 2. Try to get as predefined shorttype ("bool", "char", ...)
95
+ if ( PredefinedTypesHelper . PredefinedTypesShorthands . TryGetValue ( name , out var predefinedShortHandType ) )
96
+ {
97
+ keyWordOrType = predefinedShortHandType ;
98
+ return true ;
99
+ }
73
100
74
- if ( config . CustomTypeProvider != null )
75
- {
76
- foreach ( Type type in config . CustomTypeProvider . GetCustomTypes ( ) )
77
- {
78
- _keywords [ type . FullName ] = type ;
79
- _keywords [ type . Name ] = type ;
80
- }
81
- }
101
+ // 3. Try to get as predefined type ("Boolean", "System.Boolean", ..., "DateTime", "System.DateTime", ...)
102
+ if ( _preDefinedTypeMapping . TryGetValue ( name , out var predefinedType ) )
103
+ {
104
+ keyWordOrType = predefinedType ;
105
+ return true ;
82
106
}
83
107
84
- public bool TryGetValue ( string name , out object type )
108
+ // 4. Try to get as an enum from the system namespace
109
+ if ( _config . SupportEnumerationsFromSystemNamespace && EnumerationsFromMscorlib . PredefinedEnumerationTypes . TryGetValue ( name , out var predefinedEnumType ) )
85
110
{
86
- return _keywords . TryGetValue ( name , out type ) ;
111
+ keyWordOrType = predefinedEnumType ;
112
+ return true ;
87
113
}
114
+
115
+ // 5. Try to get as custom type
116
+ if ( _customTypeMapping . TryGetValue ( name , out var customType ) )
117
+ {
118
+ keyWordOrType = customType ;
119
+ return true ;
120
+ }
121
+
122
+ // 6. Not found, return false
123
+ keyWordOrType = null ;
124
+ return false ;
88
125
}
89
- }
126
+ }
0 commit comments