1 | #Region "Microsoft.VisualBasic::d46bd0117a924034935616586fd3bdf9, Microsoft.VisualBasic.Core\Language\Value\DefaultValue\Default.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 | ' Delegate Function |
35 | ' |
36 | ' |
37 | ' Delegate Function |
38 | ' |
39 | ' |
40 | ' Interface IDefaultValue |
41 | ' |
42 | ' Properties: DefaultValue |
43 | ' |
44 | ' Interface IsEmpty |
45 | ' |
46 | ' Properties: IsEmpty |
47 | ' |
48 | ' Structure DefaultValue |
49 | ' |
50 | ' Properties: DefaultValue, IsEmpty |
51 | ' |
52 | ' Constructor: (+2 Overloads) Sub New |
53 | ' Function: (+2 Overloads) [When], getDefault, GetNumericAssert, ToString |
54 | ' Operators: (+2 Overloads) +, (+6 Overloads) Or |
55 | ' |
56 | ' |
57 | ' |
58 | ' |
59 | ' |
60 | ' /********************************************************************************/ |
61 | |
62 | #End Region |
63 | |
64 | Imports System.Linq.Expressions |
65 | Imports System.Runtime.CompilerServices |
66 | Imports Microsoft.VisualBasic.Language.Perl |
67 | |
68 | Namespace Language.Default |
69 | |
70 | Public Delegate Function Assert(Of T)(obj As T) As Boolean |
71 | |
72 | ''' <summary> |
73 | ''' + Test of A eqauls to B? |
74 | ''' </summary> |
75 | ''' <typeparam name="T"></typeparam> |
76 | ''' <param name="x"></param> |
77 | ''' <param name="y"></param> |
78 | ''' <returns></returns> |
79 | Public Delegate Function BinaryAssert(Of T)(x As T, y As T) As Boolean |
80 | |
81 | Public Interface IDefaultValue(Of T) |
82 | ReadOnly Property DefaultValue As T |
83 | End Interface |
84 | |
85 | ''' <summary> |
86 | ''' Apply on the structure type that assert the object is null or not. |
87 | ''' </summary> |
88 | Public Interface IsEmpty |
89 | ReadOnly Property IsEmpty As Boolean |
90 | End Interface |
91 | |
92 | ''' <summary> |
93 | ''' The default value |
94 | ''' </summary> |
95 | ''' <typeparam name="T"></typeparam> |
96 | Public Structure DefaultValue(Of T) : Implements IDefaultValue(Of T) |
97 | Implements IsEmpty |
98 | |
99 | Public ReadOnly Property DefaultValue As T Implements IDefaultValue(Of T).DefaultValue |
100 | <MethodImpl(MethodImplOptions.AggressiveInlining)> |
101 | Get |
102 | If LazyValue Is Nothing Then |
103 | Return Value |
104 | Else |
105 | ' using lazy loading, if the default value takes time to creates. |
106 | Return LazyValue.Value() |
107 | End If |
108 | End Get |
109 | End Property |
110 | |
111 | Public ReadOnly Property IsEmpty As Boolean Implements IsEmpty.IsEmpty |
112 | <MethodImpl(MethodImplOptions.AggressiveInlining)> |
113 | Get |
114 | Return LazyValue Is Nothing AndAlso assert(Value) |
115 | End Get |
116 | End Property |
117 | |
118 | ''' <summary> |
119 | ''' The default value for <see cref="DefaultValue"/> |
120 | ''' </summary> |
121 | Dim Value As T |
122 | |
123 | ''' <summary> |
124 | ''' 假若生成目标值的时间比较久,可以将其申明为Lambda表达式,这样子可以进行惰性加载 |
125 | ''' </summary> |
126 | Dim LazyValue As Lazy(Of T) |
127 | |
128 | ''' <summary> |
129 | ''' asset that if target value is null? |
130 | ''' </summary> |
131 | Dim assert As Assert(Of Object) |
132 | |
133 | ''' <summary> |
134 | ''' 这个判断函数优化了对数字类型的判断 |
135 | ''' </summary> |
136 | ''' <param name="n"></param> |
137 | ''' <returns></returns> |
138 | ''' <remarks> |
139 | ''' 在VB之中,数值类型在未赋值的状态下默认值为零,意味着此时该数值的值为空 |
140 | ''' 但是不清楚这样子判断是否会出现bug? |
141 | ''' </remarks> |
142 | Public Shared Function GetNumericAssert(n As Object) As Boolean |
143 | If n Is Nothing Then |
144 | ' 可空类型的数值类型 |
145 | Return True |
146 | End If |
147 | |
148 | Select Case n.GetType |
149 | Case GetType(Integer), GetType(Long), GetType(ULong), GetType(UInteger), GetType(Short), GetType(UShort) |
150 | Return CInt(n) = 0 OrElse CDbl(n).IsNaNImaginary |
151 | Case GetType(Double), GetType(Single), GetType(Decimal) |
152 | Return CDbl(n) = 0.0 OrElse CDbl(n).IsNaNImaginary |
153 | Case Else |
154 | #If DEBUG Then |
155 | Call n.GetType.FullName.Warning |
156 | #End If |
157 | Return ExceptionHandle.Default(obj:=n) |
158 | End Select |
159 | End Function |
160 | |
161 | Sub New(value As T, Optional assert As Assert(Of Object) = Nothing) |
162 | Me.Value = value |
163 | Me.assert = assert Or defaultAssert |
164 | End Sub |
165 | |
166 | Sub New(lazy As Func(Of T), Optional assert As Assert(Of Object) = Nothing) |
167 | Me.LazyValue = lazy.AsLazy |
168 | Me.assert = assert Or defaultAssert |
169 | End Sub |
170 | |
171 | Public Function [When](expression As Boolean) As DefaultValue(Of T) |
172 | assert = Function(null) expression |
173 | Return Me |
174 | End Function |
175 | |
176 | Public Function [When](assert As Assert(Of T)) As DefaultValue(Of T) |
177 | Me.assert = Function(o) assert(DirectCast(o, T)) |
178 | Return Me |
179 | End Function |
180 | |
181 | Public Overrides Function ToString() As String |
182 | Return $"default({Value})" |
183 | End Function |
184 | |
185 | ''' <summary> |
186 | ''' Add handler |
187 | ''' </summary> |
188 | ''' <param name="[default]"></param> |
189 | ''' <param name="assert"></param> |
190 | ''' <returns></returns> |
191 | ''' |
192 | <MethodImpl(MethodImplOptions.AggressiveInlining)> |
193 | Public Shared Operator +([default] As DefaultValue(Of T), assert As Assert(Of Object)) As DefaultValue(Of T) |
194 | Return New DefaultValue(Of T) With { |
195 | .assert = assert, |
196 | .Value = [default].Value |
197 | } |
198 | End Operator |
199 | |
200 | <MethodImpl(MethodImplOptions.AggressiveInlining)> |
201 | Public Shared Operator +([default] As DefaultValue(Of T), assert As Expression(Of Func(Of Boolean))) As DefaultValue(Of T) |
202 | Return New DefaultValue(Of T) With { |
203 | .assert = Function(null) (assert.Compile())(), |
204 | .Value = [default].Value |
205 | } |
206 | End Operator |
207 | |
208 | ''' <summary> |
209 | ''' if <see cref="assert"/> is true, then will using default <see cref="value"/>, |
210 | ''' otherwise, return the source <paramref name="obj"/>. |
211 | ''' </summary> |
212 | ''' <param name="obj"></param> |
213 | ''' <param name="[default]"></param> |
214 | ''' <returns></returns> |
215 | ''' |
216 | <MethodImpl(MethodImplOptions.AggressiveInlining)> |
217 | Public Shared Operator Or(obj As T, [default] As DefaultValue(Of T)) As T |
218 | Return getDefault(obj, [default].DefaultValue, If([default].assert, ExceptionHandle.defaultHandler)) |
219 | End Operator |
220 | |
221 | <MethodImpl(MethodImplOptions.AggressiveInlining)> |
222 | Private Shared Function getDefault(value As T, [default] As T, assert As Assert(Of Object)) |
223 | Return If(assert(value), [default], value) |
224 | End Function |
225 | |
226 | <MethodImpl(MethodImplOptions.AggressiveInlining)> |
227 | Public Shared Operator Or([default] As DefaultValue(Of T), obj As T) As T |
228 | Return getDefault([default].DefaultValue, obj, If([default].assert, ExceptionHandle.defaultHandler)) |
229 | End Operator |
230 | |
231 | ''' <summary> |
232 | ''' 这个操作符允许链式计算默认值: |
233 | ''' |
234 | ''' A OR B OR C OR x OR y OR z |
235 | ''' </summary> |
236 | ''' <param name="x"></param> |
237 | ''' <param name="y"></param> |
238 | ''' <returns></returns> |
239 | <MethodImpl(MethodImplOptions.AggressiveInlining)> |
240 | Public Shared Operator Or(x As DefaultValue(Of T), y As DefaultValue(Of T)) As T |
241 | Return x.DefaultValue Or y |
242 | End Operator |
243 | |
244 | <MethodImpl(MethodImplOptions.AggressiveInlining)> |
245 | Public Shared Widening Operator CType(obj As T) As DefaultValue(Of T) |
246 | Return New DefaultValue(Of T) With { |
247 | .Value = obj, |
248 | .assert = AddressOf ExceptionHandle.Default |
249 | } |
250 | End Operator |
251 | |
252 | <MethodImpl(MethodImplOptions.AggressiveInlining)> |
253 | Public Shared Narrowing Operator CType([default] As DefaultValue(Of T)) As T |
254 | Return [default].DefaultValue |
255 | End Operator |
256 | |
257 | <MethodImpl(MethodImplOptions.AggressiveInlining)> |
258 | Public Shared Widening Operator CType(lazy As Func(Of T)) As DefaultValue(Of T) |
259 | Return New DefaultValue(Of T) With { |
260 | .LazyValue = lazy.AsLazy, |
261 | .assert = AddressOf ExceptionHandle.Default |
262 | } |
263 | End Operator |
264 | End Structure |
265 | End Namespace |