1 | #Region "Microsoft.VisualBasic::befe620a7db53198a08198cf6b5207f4, Microsoft.VisualBasic.Core\Scripting\Expressions\Selector.vb" |
2 | |
3 | ' Author: |
4 | ' |
5 | ' asuka (amethyst.asuka@gcmodeller.org) |
6 | ' xie (genetics@smrucc.org) |
7 | ' xieguigang (xie.guigang@live.com) |
8 | ' |
9 | ' Copyright (c) 2018 GPL3 Licensed |
10 | ' |
11 | ' |
12 | ' GNU GENERAL PUBLIC LICENSE (GPL3) |
13 | ' |
14 | ' |
15 | ' This program is free software: you can redistribute it and/or modify |
16 | ' it under the terms of the GNU General Public License as published by |
17 | ' the Free Software Foundation, either version 3 of the License, or |
18 | ' (at your option) any later version. |
19 | ' |
20 | ' This program is distributed in the hope that it will be useful, |
21 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of |
22 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
23 | ' GNU General Public License for more details. |
24 | ' |
25 | ' You should have received a copy of the GNU General Public License |
26 | ' along with this program. If not, see <http://www.gnu.org/licenses/>. |
27 | |
28 | |
29 | |
30 | ' /********************************************************************************/ |
31 | |
32 | ' Summaries: |
33 | |
34 | ' Module Selector |
35 | ' |
36 | ' Function: (+3 Overloads) [Select] |
37 | ' Delegate Function |
38 | ' |
39 | ' Function: [Select], ParseExpression |
40 | ' |
41 | ' |
42 | ' |
43 | ' /********************************************************************************/ |
44 | |
45 | #End Region |
46 | |
47 | Imports System.Reflection |
48 | Imports System.Runtime.CompilerServices |
49 | Imports Microsoft.VisualBasic.ComponentModel.DataSourceModel |
50 | Imports Microsoft.VisualBasic.Emit.Marshal |
51 | Imports Microsoft.VisualBasic.Language |
52 | Imports Microsoft.VisualBasic.Scripting.Runtime |
53 | |
54 | Namespace Scripting.Expressions |
55 | |
56 | ''' <summary> |
57 | ''' The property value selector |
58 | ''' </summary> |
59 | Public Module Selector |
60 | |
61 | ''' <summary> |
62 | ''' Select property value from target source collection by using a specific property name |
63 | ''' </summary> |
64 | ''' <param name="source"></param> |
65 | ''' <param name="type"></param> |
66 | ''' <param name="propertyName$"></param> |
67 | ''' <returns></returns> |
68 | <Extension> |
69 | Public Iterator Function [Select](source As IEnumerable, type As Type, propertyName$) As IEnumerable(Of Object) |
70 | Dim [property] As PropertyInfo = |
71 | type _ |
72 | .GetProperties(BindingFlags.Public Or BindingFlags.Instance) _ |
73 | .Where(Function(prop) prop.Name.TextEquals([propertyName])) _ |
74 | .FirstOrDefault |
75 | |
76 | For Each o As Object In source |
77 | Yield [property].GetValue(o, Nothing) |
78 | Next |
79 | End Function |
80 | |
81 | ''' <summary> |
82 | ''' Select property value from target source collection by using a specific property name and with a specific type casting constraint. |
83 | ''' </summary> |
84 | ''' <typeparam name="T"></typeparam> |
85 | ''' <param name="source"></param> |
86 | ''' <param name="type"></param> |
87 | ''' <param name="propertyName$"></param> |
88 | ''' <returns></returns> |
89 | <Extension> |
90 | Public Function [Select](Of T)(source As IEnumerable, type As Type, propertyName$) As IEnumerable(Of T) |
91 | Return source.Select(type, propertyName).Select(Function(o) DirectCast(o, T)) |
92 | End Function |
93 | |
94 | ''' <summary> |
95 | ''' Select all of the object elements their a specific property value and convert to a specific value type. |
96 | ''' (将对象类型之中的某一个属性筛选出来,然后转换为指定的数据类型) |
97 | ''' </summary> |
98 | ''' <typeparam name="T"></typeparam> |
99 | ''' <typeparam name="V"></typeparam> |
100 | ''' <param name="source"></param> |
101 | ''' <param name="propertyName$"> |
102 | ''' If the property name is ``$`` expression, that it means makes a type casting on it self. |
103 | ''' (如果属性名称为``$``,即引用自身,则这个函数的作用只是进行强制的``CType``类型转换) |
104 | ''' </param> |
105 | ''' <returns></returns> |
106 | <Extension> |
107 | Public Function [Select](Of T, V)(source As IEnumerable(Of T), propertyName$) As IEnumerable(Of V) |
108 | If propertyName = "$" Then |
109 | Return source.Select(Function(o) CType(CObj(o), V)) |
110 | Else |
111 | Return source.Select(GetType(T), propertyName).Select(Function(o) DirectCast(o, V)) |
112 | End If |
113 | End Function |
114 | |
115 | ''' <summary> |
116 | ''' The object value selector function pointer template |
117 | ''' </summary> |
118 | ''' <typeparam name="T"></typeparam> |
119 | ''' <param name="property$"></param> |
120 | ''' <param name="type"></param> |
121 | ''' <returns></returns> |
122 | Public Delegate Function Selector(Of T)(property$, ByRef type As Type) As Func(Of T, Object) |
123 | |
124 | ''' <summary> |
125 | ''' Where selector.(这个函数之中只有数字和字符串的比较) |
126 | ''' </summary> |
127 | ''' <typeparam name="T"></typeparam> |
128 | ''' <param name="source"></param> |
129 | ''' <param name="expression$"> |
130 | ''' ###### propertyName operator value |
131 | ''' |
132 | ''' 1. ``a = b`` |
133 | ''' 2. ``a > b`` |
134 | ''' 3. ``a < b`` |
135 | ''' 4. ``a => b`` |
136 | ''' 5. ``a <= b`` |
137 | ''' 4. ``a IN b`` |
138 | ''' |
139 | ''' ``$``符号表示对象自身 |
140 | ''' </param> |
141 | ''' <returns></returns> |
142 | <Extension> |
143 | Public Function [Select](Of T)(source As IEnumerable(Of T), expression$, Optional selector As Selector(Of T) = Nothing) As IEnumerable(Of T) |
144 | Dim type As Type = GetType(T) |
145 | Dim expr As NamedValue(Of String) = expression.ParseExpression |
146 | Dim value As Object |
147 | Dim compare As Func(Of T, Boolean) |
148 | |
149 | With expr |
150 | Dim getValue As Func(Of T, Object) |
151 | |
152 | If selector Is Nothing Then |
153 | If .Name = "$" Then |
154 | getValue = Function(x) x |
155 | Else |
156 | Dim [property] As PropertyInfo = |
157 | type _ |
158 | .GetProperties(BindingFlags.Public Or BindingFlags.Instance) _ |
159 | .Where(Function(prop) prop.Name.TextEquals(expr.Name)) _ |
160 | .FirstOrDefault |
161 | type = [property].PropertyType |
162 | getValue = Function(x) |
163 | Return [property].GetValue(x) |
164 | End Function |
165 | End If |
166 | Else |
167 | getValue = selector(.Name, type) |
168 | End If |
169 | |
170 | value = .Value.CTypeDynamic(type) |
171 | |
172 | If .Description = "=" Then |
173 | compare = Function(o) getValue(o).Equals(value) |
174 | ElseIf .Description.TextEquals("IN") Then |
175 | ' 字符串查找 |
176 | Dim s$ = CStrSafe(value) |
177 | compare = Function(o) InStr(s, CStrSafe(getValue(o))) > 0 |
178 | Else |
179 | Dim icompareValue = Val(value) ' DirectCast(value, IComparable) |
180 | |
181 | If .Description = ">" Then |
182 | compare = Function(o) |
183 | Return Val(getValue(o)) > (icompareValue) |
184 | End Function |
185 | ElseIf .Description = "<" Then |
186 | compare = Function(o) |
187 | Return Val(getValue(o)) < (icompareValue) |
188 | End Function |
189 | ElseIf .Description = "=>" Then |
190 | compare = Function(o) |
191 | Return Val(getValue(o)) >= (icompareValue) |
192 | End Function |
193 | ElseIf .Description = "<=" Then |
194 | compare = Function(o) |
195 | Return Val(getValue(o)) <= (icompareValue) |
196 | End Function |
197 | Else |
198 | Throw New NotSupportedException(expression) |
199 | End If |
200 | End If |
201 | End With |
202 | |
203 | Return source.Where(predicate:=compare) |
204 | End Function |
205 | |
206 | <Extension> |
207 | Public Function ParseExpression(expression$) As NamedValue(Of String) |
208 | Dim tmp As New List(Of Char) |
209 | Dim l As New List(Of String) |
210 | Dim source As New Pointer(Of Char)(expression) |
211 | |
212 | Do While Not source.EndRead |
213 | Dim c As Char = +source |
214 | |
215 | If c <> " "c Then |
216 | tmp += c |
217 | Else |
218 | l += New String(tmp) |
219 | tmp *= 0 |
220 | |
221 | If l.Count = 2 Then |
222 | l += New String(source.RawBuffer.Skip(source.Position).ToArray) |
223 | Exit Do |
224 | End If |
225 | End If |
226 | Loop |
227 | |
228 | If l.Count <> 3 Then |
229 | Throw New SyntaxErrorException(expression) |
230 | End If |
231 | |
232 | Return New NamedValue(Of String) With { |
233 | .Name = l(Scan0), |
234 | .Description = l(1), |
235 | .Value = l.Last |
236 | } |
237 | End Function |
238 | End Module |
239 | End Namespace |