1 #Region "Microsoft.VisualBasic::9cd3df138de15ae01780bace3f68965f, Microsoft.VisualBasic.Core\Extensions\Reflection\Reflection.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 EmitReflection
35     
36     '     Function: [Get], __getValue, API, AsLambda, Category
37     '               Collection2GenericIEnumerable, CreateObject, (+6 Overloads) Description, Enums, ExampleInfo
38     '               FullName, GetAllEnumFlags, (+3 OverloadsGetAssemblyDetails, (+2 OverloadsGetAttribute, GetDelegateInvokeEntryPoint
39     '               GetDouble, GetFullName, GetInt, (+2 OverloadsGetReadWriteProperties, GetTypeElement
40     '               GetTypesHelper, (+2 OverloadsGetValue, (+2 OverloadsGetVersion, IsInheritsFrom, IsModule
41     '               IsNumericType, ModuleVersion, NamespaceEntry, ResourcesSatellite, Source
42     '               Usage
43     
44     '     Sub: RunApp
45     
46     ' /********************************************************************************/
47
48 #End Region
49
50 Imports System.ComponentModel
51 Imports System.Reflection
52 Imports System.Runtime.CompilerServices
53 Imports Microsoft.VisualBasic.ApplicationServices
54 Imports Microsoft.VisualBasic.ApplicationServices.Development
55 Imports Microsoft.VisualBasic.CommandLine.Reflection
56 Imports Microsoft.VisualBasic.Emit.Delegates
57 Imports Microsoft.VisualBasic.FileIO
58 Imports Microsoft.VisualBasic.Language
59 Imports Microsoft.VisualBasic.Language.Default
60 Imports Microsoft.VisualBasic.Linq
61 Imports Microsoft.VisualBasic.Scripting
62 Imports Microsoft.VisualBasic.Scripting.MetaData
63 Imports Microsoft.VisualBasic.Serialization.JSON
64 Imports DevAssmInfo = Microsoft.VisualBasic.ApplicationServices.Development.AssemblyInfo
65
66 ''' <summary>
67 ''' Some common used reflection operation extension at here.
68 ''' </summary>
69 <Package("Emit.Reflection", Category:=APICategories.SoftwareTools, Publisher:="xie.guigang@live.com")>
70 Public Module EmitReflection
71
72     <MethodImpl(MethodImplOptions.AggressiveInlining)>
73     <Extension>
74     Public Function ResourcesSatellite(assembly As Assembly) As ResourcesSatellite
75         Return New ResourcesSatellite(assembly)
76     End Function
77
78     ''' <summary>
79     ''' Try to handle for the bugs in VisualBasic language: 
80     ''' 
81     ''' https://github.com/dotnet/roslyn/issues/23050
82     ''' </summary>
83     ''' <param name="assm"></param>
84     ''' <returns></returns>
85     Public Function GetTypesHelper(assm As Assembly) As Type()
86         Try
87             Return assm.GetTypes
88
89         Catch ex As Exception When TypeOf ex Is ReflectionTypeLoadException
90             Dim details = DirectCast(ex, ReflectionTypeLoadException)
91             Dim msg$ = details.LoaderExceptions _
92                     .Select(Function(e) e.Message) _
93                     .ToArray _
94                     .GetJson
95
96             Throw New Exception(msg, ex)
97
98         Catch ex As Exception
99
100             Throw
101
102         End Try
103     End Function
104
105     <MethodImpl(MethodImplOptions.AggressiveInlining)>
106     <Extension>
107     Public Function AsLambda(Of T)(assert As Assert(Of T)) As Func(Of T, Boolean)
108         ' System.ArgumentException: '无法绑定到目标方法,因其签名或安全透明度与委托类型的签名或安全透明度不兼容。
109         ' assert.Method.CreateDelegate(GetType(Func(Of T, Boolean)))
110         Return Function(x) assert(x)
111     End Function
112
113     <Extension>
114     Public Function Source(m As MemberInfo) As String
115         Return m.DeclaringType.FullName & "::" & m.Name
116     End Function
117
118     ''' <summary>
119     ''' Run external [.NET] Program from RAM Memory
120     ''' </summary>
121     ''' <param name="app"></param>
122     ''' <param name="CLI"></param>
123     ''' <param name="cs">Going to running a c# program?</param>
124     ''' <remarks>
125     ''' http://www.codeproject.com/Tips/1108105/Run-external-NET-Program-from-RAM-Memory
126     ''' 
127     ''' Run external app directly from RAM. You can load the specific file into a ``Byte[]`` Array 
128     ''' with a ``StreamReader()`` or even download it from WEB via a direct link provided. 
129     ''' If you loaded the file from disk, you can delete it if you want after it has been loaded 
130     ''' by a ``StreamReader()``.
131     ''' </remarks>
132     Public Sub RunApp(app As StringOptional CLI As String = ""Optional cs As Boolean = False)
133         Dim bufs As Byte() = app.GetMapPath.ReadBinary ' Works on both local file or network file. 
134
135         Try
136             Dim assm As Assembly = Assembly.Load(bufs) ' or assm = Reflection.Assembly.Load(New WebClient().DownloadData("https://...."))
137             Dim method As MethodInfo = assm.EntryPoint
138
139             If (Not method Is NothingThen
140                 Dim o As Object = assm.CreateInstance(method.Name)
141
142                 If String.IsNullOrEmpty(CLI) Then
143                     Dim null As Object() = If(cs, {Nothing}, Nothing)
144                     Call method.Invoke(o, null)
145                 Else
146                     ' if your app receives parameters
147                     Call method.Invoke(o, New Object() {CommandLine.GetTokens(CLI)})
148                 End If
149             Else
150                 Throw New NullReferenceException($"'{app}' No App Entry Point was found!")
151             End If
152         Catch ex As Exception
153             ex = New Exception("CLI:=" & CLI, ex)
154             ex = New Exception("app:=" & app, ex)
155 #If DEBUG Then
156             Call ex.PrintException
157 #End If
158             Throw ex
159         End Try
160     End Sub
161
162 #Region "IsNumericType"
163     ''' <summary>
164     ''' Determines whether the specified value is of numeric type.
165     ''' </summary>
166     ''' <param name="o">The object to check.</param>
167     ''' <returns>
168     ''' true if o is a numeric type; otherwise, false.
169     ''' </returns>
170     Public Function IsNumericType(o As ObjectAs Boolean
171         Return (TypeOf o Is Byte OrElse
172             TypeOf o Is SByte OrElse
173             TypeOf o Is Short OrElse
174             TypeOf o Is UShort OrElse
175             TypeOf o Is Integer OrElse
176             TypeOf o Is UInteger OrElse
177             TypeOf o Is Long OrElse
178             TypeOf o Is ULong OrElse
179             TypeOf o Is Single OrElse
180             TypeOf o Is Double OrElse
181             TypeOf o Is Decimal)
182     End Function
183 #End Region
184
185     <Extension>
186     Public Function GetDouble(field As FieldInfo, Optional obj As Object = NothingAs Double
187         Return CType(field.GetValue(obj), Double)
188     End Function
189
190     <Extension>
191     Public Function GetInt(field As FieldInfo, Optional obj As Object = NothingAs Integer
192         Return CType(field.GetValue(obj), Integer)
193     End Function
194
195     ''' <summary>
196     '''
197     ''' </summary>
198     ''' <param name="type"></param>
199     ''' <param name="[nameOf]"></param>
200     ''' <returns></returns>
201     <Extension> Public Function API(type As Type, [nameOf] As StringOptional strict As Boolean = FalseAs String
202 #If NET_40 = 0 Then
203         Dim methods = type.GetMethods(BindingFlags.Public Or BindingFlags.Static)
204         Dim mBase As MethodInfo = (From m As MethodInfo In methods
205                                    Where String.Equals([nameOf], m.Name)
206                                    Select m).FirstOrDefault
207         If mBase Is Nothing Then
208 NULL:       If Not strict Then
209                 Return [nameOf]
210             Else
211                 Return ""
212             End If
213         Else
214             Dim APIExport As ExportAPIAttribute = mBase.GetCustomAttribute(Of ExportAPIAttribute)
215             If APIExport Is Nothing Then
216                 GoTo NULL
217             Else
218                 Return APIExport.Name
219             End If
220         End If
221 #Else
222         Throw New NotSupportedException
223 #End If
224     End Function
225
226     <ExportAPI("GET.Assembly.Details")>
227     <Extension>
228     Public Function GetAssemblyDetails(path As StringAs DevAssmInfo
229         Return Assembly.LoadFile(path).FromAssembly
230     End Function
231
232     <ExportAPI("GET.Assembly.Details")>
233     <Extension>
234     Public Function GetAssemblyDetails(def As Type) As DevAssmInfo
235         Return def.Assembly.FromAssembly
236     End Function
237
238     <ExportAPI("GET.Assembly.Details")>
239     <Extension>
240     Public Function GetAssemblyDetails(assm As Assembly) As DevAssmInfo
241         Return assm.FromAssembly
242     End Function
243
244     ''' <summary>
245     ''' 得到集合类型的对象之中的元素类型
246     ''' </summary>
247     ''' <param name="type"></param>
248     ''' <param name="strict"></param>
249     ''' <returns></returns>
250     <Extension> Public Function GetTypeElement(type As Type, strict As BooleanAs Type
251         If type.IsInheritsFrom(GetType(Array)) Then
252             Return type.GetElementType
253         End If
254         If type.IsInheritsFrom(GetType(List(Of ))) Then
255             Return type.GetGenericArguments.First
256         End If
257         If type.IsInheritsFrom(GetType(Dictionary(Of ,))) Then
258             Dim keyValue As Type() = type.GetGenericArguments
259             Return GetType(KeyValuePair(Of ,)).MakeGenericType(keyValue)
260         End If
261         If type.ImplementInterface(GetType(IEnumerable)) Then
262             type = type.GetInterfaces.Where(Function(i) InStr(i.Name, "IEnumerable") = 1).First
263             Return type.GenericTypeArguments.First
264         End If
265
266         If strict Then
267             Return Nothing
268         Else
269             Throw New NotImplementedException
270         End If
271     End Function
272
273     ''' <summary>
274     '''
275     ''' </summary>
276     ''' <param name="Product">.NET EXE/DLL assembly path</param>
277     ''' <returns></returns>
278     '''
279     <ExportAPI("Get.Version")>
280     Public Function GetVersion(Product As StringAs Version
281         Dim assm As Assembly = Assembly.LoadFile(Product)
282         Return assm.GetVersion
283     End Function
284
285     ''' <summary>
286     ''' 如果不存在<see cref="DescriptionAttribute"/>定义则会返回空白字符串
287     ''' </summary>
288     ''' <param name="prop"></param>
289     ''' <returns></returns>
290     <ExportAPI("Get.Description")>
291     <Extension> Public Function Description(prop As PropertyInfo) As String
292         Dim attrs As Object() = prop.GetCustomAttributes(GetType(DescriptionAttribute), inherit:=True)
293
294         If attrs.IsNullOrEmpty Then
295             Return ""
296         Else
297             Return DirectCast(attrs(Scan0), DescriptionAttribute).Description
298         End If
299     End Function
300
301     ''' <summary>
302     ''' Gets the <see cref="AssemblyFileVersionAttribute"/> value from the type defined assembly.
303     ''' </summary>
304     ''' <param name="type"></param>
305     ''' <returns></returns>
306     ''' 
307     <ExportAPI("Get.Version")>
308     <Extension>
309     Public Function ModuleVersion(type As Type) As String
310         Return type.Assembly.GetVersion.ToString
311     End Function
312
313     ''' <summary>
314     '''
315     ''' </summary>
316     ''' <param name="assm">.NET EXE/DLL assembly</param>
317     ''' <returns></returns>
318     '''
319     <ExportAPI("Get.Version")>
320     <Extension> Public Function GetVersion(assm As Assembly) As Version
321 #If NET_40 = 0 Then
322         Dim attrs As IEnumerable(Of CustomAttributeData) = assm.CustomAttributes
323         Dim vLQuery As CustomAttributeTypedArgument =
324             LinqAPI.DefaultFirst(Of CustomAttributeTypedArgument) <=
325                     From attr As CustomAttributeData
326                     In attrs
327                     Where attr.AttributeType.Equals(GetType(AssemblyFileVersionAttribute))
328                     Select value = attr.ConstructorArguments(Scan0)
329
330         If vLQuery.Value Is Nothing Then
331             Return New Version("1.0.0.0")
332         Else
333             Return New Version(Scripting.ToString(vLQuery.Value))
334         End If
335 #Else
336         Throw New NotSupportedException
337 #End If
338     End Function
339
340     ''' <summary>
341     ''' 目标类型是不是VisualBasic之中的``Module``模块类型?
342     ''' </summary>
343     ''' <param name="typeDef"></param>
344     ''' <returns></returns>
345     <ExportAPI("Is.Module")>
346     <Extension> Public Function IsModule(typeDef As Type) As Boolean
347         If typeDef.Name.IndexOf("$") > -1 OrElse typeDef.Name.IndexOf("`") > -1 Then
348             Return False ' 匿名类型
349         End If
350
351         Return typeDef.IsClass
352     End Function
353
354     ''' <summary>
355     ''' 出错会返回空集合
356     ''' </summary>
357     ''' <typeparam name="T"></typeparam>
358     ''' <typeparam name="TProperty"></typeparam>
359     ''' <param name="collection"></param>
360     ''' <param name="Name">使用System.NameOf()操作符来获取</param>
361     ''' <returns></returns>
362     <Extension> Public Function [Get](Of T, TProperty)(collection As ICollection(Of T), Name As StringOptional TrimNull As Boolean = TrueAs TProperty()
363         Dim Type As Type = GetType(T)
364         Dim Properties = (From p In Type.GetProperties(BindingFlags.Public Or BindingFlags.Instance)
365                           Where String.Equals(p.Name, Name)
366                           Select p).ToArray
367         If Properties.IsNullOrEmpty Then
368             Return New TProperty() {}
369         End If
370
371         Dim [Property] As PropertyInfo = Properties.First
372         Dim resultBuffer As TProperty()
373
374         If TrimNull Then
375             resultBuffer = (From obj As T In collection.AsParallel
376                             Let value As Object = [Property].GetValue(obj, Nothing)
377                             Where Not value Is Nothing
378                             Select DirectCast(value, TProperty)).ToArray
379         Else
380             resultBuffer = (From obj As T In collection.AsParallel
381                             Let value As Object = [Property].GetValue(obj, Nothing)
382                             Select If(value Is NothingNothingDirectCast(value, TProperty))).ToArray
383         End If
384
385         Return resultBuffer
386     End Function
387
388     ''' <summary>
389     ''' Is type <paramref name="a"/> inherits from <paramref name="base"/> type?
390     ''' </summary>
391     ''' <param name="a">继承类型继承自基本类型,具备有基本类型的所有特性</param>
392     ''' <param name="base">基本类型</param>
393     ''' <param name="strict">
394     ''' + 这个参数是为了解决比较来自不同的assembly文件之中的相同类型的比较,但是这个可能会在类型转换出现一些BUG
395     ''' + 假若不严格要求的话,那么则两种类型相等的时候也会被算作为继承关系
396     ''' + 假若是非严格判断,那么对于泛型而言,只要基本类型也相等也会被判断为成立的继承关系,这个是为了<see cref="Activity"/>操作设计的
397     ''' 
398     ''' </param>
399     ''' <param name="depth">类型继承的距离值,当这个值越大的时候,说明二者的继承越远,当进行函数重载判断的时候,选择这个距离值越小的越好</param>
400     ''' <returns></returns>
401     ''' <remarks>假若两个类型是来自于不同的assembly文件的话,即使这两个类型是相同的对象,也会无法判断出来</remarks>
402     <ExportAPI("Is.InheritsFrom")>
403     <Extension> Public Function IsInheritsFrom(a As Type, base As Type, Optional strict As Boolean = TrueOptional ByRef depth% = -1) As Boolean
404         Dim baseType As Type = a.BaseType
405
406         If Not strict Then
407             ' 在这里返回结果的话,depth为-1
408
409             If a Is base Then
410                 Return True
411             End If
412
413             If a.IsGenericType AndAlso base.IsGenericType Then
414                 ' 2017-3-12
415                 GetType(Dictionary(Of StringDouble)).IsInheritsFrom(GetType(Dictionary(Of ,)))
416
417                 If a.GetGenericTypeDefinition.Equals(base) Then
418                     Return True
419                 End If
420             End If
421         End If
422
423         Do While Not baseType Is Nothing
424             depth += 1
425
426             If baseType.Equals(base) Then
427                 Return True
428             ElseIf Not strict AndAlso (baseType.FullName = base.FullName) Then
429                 Return True
430             Else
431                 baseType = baseType.BaseType
432             End If
433         Loop
434
435         Return False
436     End Function
437
438     ''' <summary>
439     ''' 如果有<see cref="system.ComponentModel.DescriptionAttribute"/>标记,则会返回该标记的字符串数据,假若没有则只会返回类型的名称
440     ''' </summary>
441     ''' <typeparam name="T"></typeparam>
442     ''' <returns></returns>
443     Public Function Description(Of T)() As String
444         Dim typeRef As Type = GetType(T)
445         Return typeRef.Description
446     End Function
447
448     ''' <summary>
449     ''' 如果有<see cref="system.ComponentModel.DescriptionAttribute"/>标记,则会返回该标记的字符串数据,假若没有则只会返回类型的名称
450     ''' </summary>
451     ''' <returns></returns>
452     '''
453     <ExportAPI("Get.Description")>
454     <Extension> Public Function Description(typeRef As Type) As String
455         Dim CustomAttrs As Object() = typeRef.GetCustomAttributes(GetType(DescriptionAttribute), inherit:=False)
456
457         If Not CustomAttrs.IsNullOrEmpty Then
458             Return CType(CustomAttrs(Scan0), DescriptionAttribute).Description
459         Else
460             Return typeRef.Name
461         End If
462     End Function
463
464 #If FRAMEWORD_CORE Then
465     ''' <summary>
466     ''' Get the description data from a enum type value, if the target have no <see cref="DescriptionAttribute"></see> attribute data
467     ''' then function will return the string value from the ToString() function.
468     ''' </summary>
469     ''' <param name="value"></param>
470     ''' <returns></returns>
471     ''' <remarks></remarks>
472     <ExportAPI("Get.Description",
473                Info:="Get the description data from a enum type value, if the target have no <see cref=""DescriptionAttribute""></see> attribute data then function will return the string value from the ToString() function.")>
474     <Extension> Public Function Description(value As [Enum]) As String
475 #Else
476     ''' <summary>
477     ''' Get the description data from a enum type value, if the target have no <see cref="DescriptionAttribute"></see> attribute data
478     ''' then function will return the string value from the ToString() function.
479     ''' </summary>
480     ''' <param name="e"></param>
481     ''' <returns></returns>
482     ''' <remarks></remarks>
483     <Extension> Public Function Description(value As [Enum]) As String
484 #End If
485         Dim type As Type = value.GetType()
486         Dim s As String = value.ToString
487         Dim memInfos As MemberInfo() = type.GetMember(name:=s)
488
489         If memInfos.IsNullOrEmpty Then
490             Return s
491         End If
492
493         Return memInfos _
494             .First _
495             .Description([default]:=s)
496     End Function
497
498     ''' <summary>
499     ''' 获取得到定义该类型成员之上的<see cref="DescriptionAttribute"/>值或者默认定义
500     ''' </summary>
501     ''' <param name="m"></param>
502     ''' <param name="default$"></param>
503     ''' <returns></returns>
504     <Extension> Public Function Description(m As MemberInfo, Optional default$ = NothingAs String
505         Dim customAttrs() = m.GetCustomAttributes(
506             GetType(DescriptionAttribute),
507             inherit:=False)
508
509         If Not customAttrs.IsNullOrEmpty Then
510             Return DirectCast(customAttrs(Scan0), DescriptionAttribute).Description
511         Else
512             Return [default]
513         End If
514     End Function
515
516     <Extension> Public Function Category(m As MemberInfo, Optional default$ = NothingAs String
517         Dim customAttrs() = m.GetCustomAttributes(
518            GetType(CategoryAttribute),
519            inherit:=False)
520
521         If Not customAttrs.IsNullOrEmpty Then
522             Return DirectCast(customAttrs(Scan0), CategoryAttribute).Category
523         Else
524             Return [default]
525         End If
526     End Function
527
528     ''' <summary>
529     ''' Get array value from the input flaged enum <paramref name="value"/>.
530     ''' </summary>
531     ''' <typeparam name="T"></typeparam>
532     ''' <param name="value"></param>
533     ''' <returns></returns>
534     Public Function GetAllEnumFlags(Of T As Structure)(value As T) As T()
535         Dim type As Type = GetType(T)
536         Dim array As New List(Of T)
537         Dim enumValue As [Enum] = CType(CObj(value), [Enum])
538
539         For Each flag As [Enum] In Enums(Of T)().Select(Function(o) CType(CObj(o), [Enum]))
540             If enumValue.HasFlag(flag) Then
541                 array += DirectCast(CObj(flag), T)
542             End If
543         Next
544
545         Return array
546     End Function
547
548     ''' <summary>
549     ''' Enumerate all of the enum values in the specific <see cref="System.Enum"/> type data.(只允许枚举类型,其他的都返回空集合)
550     ''' </summary>
551     ''' <typeparam name="T">泛型类型约束只允许枚举类型,其他的都返回空集合</typeparam>
552     ''' <returns></returns>
553     Public Function Enums(Of T As Structure)() As T()
554         Dim EnumType As Type = GetType(T)
555         If Not EnumType.IsInheritsFrom(GetType(System.Enum)) Then
556             Return Nothing
557         End If
558
559         Dim EnumValues As Object() =
560             Scripting _
561             .CastArray(Of System.Enum)(EnumType.GetEnumValues) _
562             .Select(Of Object)(Function(ar)
563                                    Return DirectCast(ar, Object)
564                                End Function) _
565             .ToArray
566         Dim values As T() = EnumValues _
567             .Select(Of T)(Function([enum]) DirectCast([enum], T)) _
568             .ToArray
569         Return values
570     End Function
571
572     ''' <summary>
573     ''' Gets all of the can read and write access property from a type define.
574     ''' </summary>
575     ''' <param name="type"></param>
576     ''' <returns></returns>
577 #If FRAMEWORD_CORE Then
578     <ExportAPI("Get.Properties")>
579     <Extension> Public Function GetReadWriteProperties(type As Type) As PropertyInfo()
580 #Else
581     <Extension> Public Function GetReadWriteProperties(type As System.Type) As System.Reflection.PropertyInfo()
582 #End If
583         Dim LQuery = LinqAPI.Exec(Of PropertyInfo) <=
584  _
585             From p As PropertyInfo
586             In type.GetProperties
587             Where p.CanRead AndAlso p.CanWrite
588             Select p
589
590         Return LQuery
591     End Function
592
593     ''' <summary>
594     ''' Get object usage information
595     ''' </summary>
596     ''' <param name="m"></param>
597     ''' <returns></returns>
598     <Extension> Public Function Usage(m As MemberInfo) As String
599         Try
600             Dim attr As UsageAttribute = m.GetCustomAttribute(Of UsageAttribute)
601             Return attr.UsageInfo
602         Catch ex As Exception
603             Return Nothing
604         End Try
605     End Function
606
607     ''' <summary>
608     ''' Get example code of the <see cref="Usage"/>
609     ''' </summary>
610     ''' <param name="m"></param>
611     ''' <returns></returns>
612     <Extension> Public Function ExampleInfo(m As MemberInfo) As String
613         Try
614             Dim attr As ExampleAttribute = m.GetCustomAttribute(Of ExampleAttribute)
615             Return attr.ExampleInfo
616         Catch ex As Exception
617             Return Nothing
618         End Try
619     End Function
620
621     ''' <summary>
622     ''' 只对属性有效,出错会返回空值
623     ''' </summary>
624     ''' <param name="obj"></param>
625     ''' <param name="Name"></param>
626     ''' <returns></returns>
627     '''
628     <ExportAPI("GetValue")>
629     <Extension> Public Function GetValue(Type As Type, obj As Object, Name As StringAs Object
630         Try
631             Return __getValue(Type, obj, Name)
632         Catch ex As Exception
633             Return App.LogException(ex, $"{GetType(Extensions).FullName}::{NameOf(GetValue)}")
634         End Try
635     End Function
636
637     Private Function __getValue(Type As Type, obj As Object, Name As StringAs Object
638         Dim [property] = Type.GetProperty(Name, BindingFlags.Public Or BindingFlags.Instance)
639         If [property] Is Nothing Then
640             Return Nothing
641         End If
642         Dim value = [property].GetValue(obj, Nothing)
643         Return value
644     End Function
645
646     ''' <summary>
647     ''' 只对属性有效,出错会返回空值
648     ''' </summary>
649     ''' <param name="obj"></param>
650     ''' <param name="Name"></param>
651     ''' <returns></returns>
652     <Extension> Public Function GetValue(Of T)(Type As Type, obj As Object, Name As StringAs T
653         Dim value = Type.GetValue(obj, Name)
654         If value Is Nothing Then
655             Return Nothing
656         End If
657         Dim cast As T = DirectCast(value, T)
658         Return cast
659     End Function
660
661 #If NET_40 = 0 Then
662
663     ''' <summary>
664     ''' Try convert the type specific collection data type into a generic enumerable collection data type.(尝试将目标集合类型转换为通用的枚举集合类型)
665     ''' </summary>
666     ''' <param name="Type">The type specific collection data type.(特定类型的集合对象类型,当然也可以是泛型类型)</param>
667     ''' <returns>If the target data type is not a collection data type then the original data type will be returns and the function displays a warning message.</returns>
668     ''' <remarks></remarks>
669     '''
670     <ExportAPI("Collection2GenericIEnumerable"Info:="Try convert the type specific collection data type into a generic enumerable collection data type.")>
671     <Extension> Public Function Collection2GenericIEnumerable(
672                                                         Type As Type,
673                                                         Optional DebuggerMessage As Boolean = TrueAs Type
674
675         If Array.IndexOf(Type.GetInterfaces, GetType(IEnumerable)) = -1 Then
676 EXIT_:      If DebuggerMessage Then Call $"[WARN] Target type ""{Type.FullName}"" is not a collection type!".__DEBUG_ECHO
677             Return Type
678         End If
679
680         Dim GenericType As Type = GetType(Generic.IEnumerable(Of )) 'Type.GetType("System.Collections.Generic.IEnumerable")
681         Dim ElementType As Type = Type.GetElementType
682
683         If ElementType Is Nothing Then
684             Dim Generics = Type.GenericTypeArguments
685
686             If Generics.IsNullOrEmpty Then
687                 GoTo EXIT_
688             Else
689                 ElementType = Generics(Scan0)
690             End If
691         End If
692
693         GenericType = GenericType.MakeGenericType({ElementType})
694
695         Return GenericType
696     End Function
697 #End If
698
699     ''' <summary>
700     ''' Get the method reflection entry point for a anonymous lambda expression.
701     ''' (当函数返回Nothing的时候说明目标对象不是一个函数指针)
702     ''' </summary>
703     ''' <param name="obj"></param>
704     ''' <returns></returns>
705     ''' <remarks></remarks>
706     '''
707     <ExportAPI("Delegate.GET_Invoke"Info:="Get the method reflection entry point for a anonymous lambda expression.")>
708     Public Function GetDelegateInvokeEntryPoint(obj As ObjectAs MethodInfo
709         Dim type As Type = obj.GetType
710         Dim entryPoint = LinqAPI.DefaultFirst(Of MethodInfo) _
711  _
712             () <= From methodInfo As MethodInfo
713                   In type.GetMethods
714                   Where String.Equals(methodInfo.Name, "Invoke")
715                   Select methodInfo
716
717         Return entryPoint
718     End Function
719
720     ''' <summary>
721     ''' Get the scripting namespace value from <see cref="[Namespace]"/>
722     ''' </summary>
723     ''' <param name="app"></param>
724     ''' <returns></returns>
725     '''
726     <ExportAPI("Get.API.Namespace")>
727     <Extension> Public Function NamespaceEntry(app As Type, Optional nullWrapper As Boolean = FalseAs [Namespace]
728         Dim attr As Object() = Nothing
729         Try
730             attr = app.GetCustomAttributes(GetType([Namespace]), True)
731         Catch ex As Exception
732             Call LogException(New Exception(app.FullName, ex))
733         End Try
734         If attr.IsNullOrEmpty Then
735             Dim descr$ = app.FullName
736             If nullWrapper Then
737                 descr = $"< {descr} >"
738             End If
739             Return New [Namespace](app.Name, descr, True)
740         Else
741             Return DirectCast(attr(Scan0), [Namespace])
742         End If
743     End Function
744
745     ''' <summary>
746     ''' Gets the full name of a method reflection meta data.
747     ''' </summary>
748     ''' <param name="method"></param>
749     ''' <param name="IncludeAssembly"></param>
750     ''' <returns></returns>
751     <ExportAPI("Get.FullName")>
752     <Extension> Public Function GetFullName(method As MethodBase, Optional IncludeAssembly As Boolean = FalseAs String
753         Dim Name As String = $"{method.DeclaringType.FullName}::{method.ToString}"
754         If Not IncludeAssembly Then
755             Return Name
756         Else
757             Return $"{method.DeclaringType.Module.Assembly.Location.ToFileURL}!{Name}"
758         End If
759     End Function
760
761     <ExportAPI("Get.FullName")>
762     <Extension> Public Function FullName(Method As MethodInfo, Optional IncludeAssembly As Boolean = FalseAs String
763         Return GetFullName(Method, IncludeAssembly)
764     End Function
765
766     ''' <summary>
767     ''' Get the specific type of custom attribute from a property.
768     ''' If the target custom attribute is not declared on the target, then this function returns nothing.
769     ''' (从一个属性对象中获取特定的自定义属性对象)
770     ''' </summary>
771     ''' <typeparam name="T">The type of the custom attribute.(自定义属性的类型)</typeparam>
772     ''' <param name="Property">Target property object.(目标属性对象)</param>
773     ''' <returns></returns>
774     ''' <remarks></remarks>
775     <Extension> Public Function GetAttribute(Of T As Attribute)([Property] As MemberInfo) As T
776         Dim attrType As Type = GetType(T)
777         Dim attrs As Object() = [Property].GetCustomAttributes(attrType, True)
778
779         If Not attrs Is Nothing AndAlso attrs.Length = 1 Then
780             Dim CustomAttr As T = CType(attrs(Scan0), T)
781
782             If Not CustomAttr Is Nothing Then
783                 Return CustomAttr
784             End If
785         Else
786             attrs = [Property].GetCustomAttributes(attrType, False)
787             If Not attrs.IsNullOrEmpty Then
788                 Return DirectCast(attrs(Scan0), T)
789             End If
790         End If
791
792         Return Nothing
793     End Function
794
795     ''' <summary>
796     ''' Get the specific type of custom attribute from a property.
797     ''' (从一个属性对象中获取特定的自定义属性对象,找不到的话,就会返回空值)
798     ''' </summary>
799     ''' <typeparam name="T">The type of the custom attribute.(自定义属性的类型)</typeparam>
800     ''' <param name="Property">Target property object.(目标属性对象)</param>
801     ''' <returns></returns>
802     ''' <remarks></remarks>
803     <Extension> Public Function GetAttribute(Of T As Attribute)([Property] As PropertyInfo) As T
804         Dim Attributes As Object() = [Property].GetCustomAttributes(GetType(T), True)
805
806         If Not Attributes Is Nothing AndAlso Attributes.Length = 1 Then
807             Dim CustomAttr As T = CType(Attributes(0), T)
808
809             If Not CustomAttr Is Nothing Then
810                 Return CustomAttr
811             End If
812         End If
813         Return Nothing
814     End Function
815
816 #If NET_40 = 0 Then
817
818     ''' <summary>
819     '''
820     ''' </summary>
821     ''' <typeparam name="T"></typeparam>
822     ''' <param name="args">构造函数里面的参数信息</param>
823     ''' <returns></returns>
824     Public Function CreateObject(Of T)(args As Object(),
825                                        Optional throwEx As Boolean = True,
826                                        <CallerMemberName> Optional caller As String = ""As T
827         Try
828             Dim obj As Object =
829                 Activator.CreateInstance(GetType(T), args)
830             Return DirectCast(obj, T)
831         Catch ex As Exception
832             Dim params As String() = args _
833                 .Select(Function(x) x.GetType.FullName & " ==> " & GetObjectJson(x, x.GetType)) _
834                 .ToArray
835             ex = New Exception(String.Join(vbCrLf, params), ex)
836             ex = New Exception("@" & caller, ex)
837
838             Call App.LogException(ex)
839
840             If throwEx Then
841                 Throw ex
842             Else
843                 Return Nothing
844             End If
845         End Try
846     End Function
847 #End If
848 End Module