| 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 |