1 #Region "Microsoft.VisualBasic::e65ac0e10a02ece50ebe67cb3f1cabe6, Microsoft.VisualBasic.Core\Extensions\Reflection\Parameters\ParamLogUtility.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 ParamLogUtility
35     
36     '         Function: (+3 Overloads) Acquire, GetMyCaller, InitTable
37     
38     '         Sub: AddProvidedParamaterDetail
39     
40     
41     ' /********************************************************************************/
42
43 #End Region
44
45 Imports System.Linq.Expressions
46 Imports System.Reflection
47 Imports System.Runtime.CompilerServices
48 Imports Microsoft.VisualBasic.ComponentModel.Collection
49 Imports Microsoft.VisualBasic.ComponentModel.DataSourceModel
50 Imports Microsoft.VisualBasic.Language
51
52 Namespace Emit.Parameters
53
54     ''' <summary>
55     ''' Exception is a common issue in projects. To track this exception, we use error loggers 
56     ''' which only log the exception detail and some other information if you want to. 
57     ''' But hardly do we get any idea for which input set(parameters and its values) a 
58     ''' particular method is throwing the error.
59     ''' </summary>
60     ''' <remarks>
61     ''' https://www.codeproject.com/tips/795865/log-all-parameters-that-were-passed-to-some-method
62     ''' </remarks>
63     Public Module ParamLogUtility
64
65         Public Function GetMyCaller() As MethodBase
66             ' [2] a()
67             ' [1]  ---> b()  ' my caller is a()
68             ' [0]  ---> GetMyCaller  
69             Return New StackTrace().GetFrame(2).GetMethod()
70         End Function
71
72         Public Function Acquire(ParamArray providedParameters As Expression(Of Func(Of Object))()) As Dictionary(Of Value)
73             Dim currentMethod As MethodBase = New StackTrace().GetFrame(1).GetMethod()
74             Return currentMethod.Acquire(providedParameters)
75         End Function
76
77         Public Function Acquire(Of T)(ParamArray providedParameters As Expression(Of Func(Of Object))()) As Dictionary(Of Value)
78             Dim type As Type = GetType(T)
79             Dim out As Dictionary(Of Value) = ParamLogUtility.Acquire(providedParameters)
80             out -= out.Keys.Where(Function(k) Not out(k).Type.Equals(type))
81             Return out
82         End Function
83
84         <Extension>
85         Public Function Acquire(currentMethod As MethodBase, ParamArray providedParameters As Expression(Of Func(Of Object))()) As Dictionary(Of Value)
86             Dim out As New Dictionary(Of Value)
87             Set class and current method info
88             Dim trace As New NamedValue(Of MethodBase) With {
89                 .Name = currentMethod.Name,
90                 .Value = currentMethod
91             }
92
93             Get current methods paramaters
94             'Dim _methodParamaters As New Dictionary(Of String, Type)()
95             'Call (From aParamater As ParameterInfo
96             '      In currentMethod.GetParameters
97             '      Select New With {
98             '          .Name = aParamater.Name,
99             '          .DataType = aParamater.ParameterType
100             '}).AsList() _
101             '  .ForEach(Sub(obj) _methodParamaters.Add(obj.Name, obj.DataType))
102
103             Get provided methods paramaters
104             For Each aExpression In providedParameters
105                 Dim bodyType As Expression = aExpression.Body
106
107                 If TypeOf bodyType Is MemberExpression Then
108                     Call out.AddProvidedParamaterDetail(DirectCast(aExpression.Body, MemberExpression), trace)
109                 ElseIf TypeOf bodyType Is UnaryExpression Then
110                     Dim unaryExpression As UnaryExpression = DirectCast(aExpression.Body, UnaryExpression)
111                     Call out.AddProvidedParamaterDetail(DirectCast(unaryExpression.Operand, MemberExpression), trace)
112                 Else
113                     Throw New Exception("Expression type unknown.")
114                 End If
115             Next
116
117             Return out
118         End Function
119
120         <Extension>
121         Private Sub AddProvidedParamaterDetail(out As Dictionary(Of Value), memberExpression As MemberExpression, trace As NamedValue(Of MethodBase))
122             Dim constantExpression As ConstantExpression = DirectCast(memberExpression.Expression, ConstantExpression)
123             Dim name As String = memberExpression.Member.Name
124             Dim value = DirectCast(memberExpression.Member, FieldInfo).GetValue(constantExpression.Value)
125             Dim type As Type = value.[GetType]()
126
127             name = name.Replace("$VB$Local_""")
128             out += New Value With {
129                 .Name = name,
130                 .Type = type,
131                 .Value = value,
132                 .Trace = trace
133             }
134         End Sub
135
136         <Extension>
137         Public Function InitTable(caller As MethodBase, array As Expression(Of Func(Of Object()))) As Dictionary(Of Value)
138             Dim unaryExpression As NewArrayExpression = DirectCast(array.Body, NewArrayExpression)
139             Dim arrayData As UnaryExpression() = unaryExpression _
140                 .Expressions _
141                 .Select(Function(e) DirectCast(e, UnaryExpression)) _
142                 .ToArray
143             Dim out As New Dictionary(Of Value)
144             Dim trace As New NamedValue(Of MethodBase) With {
145                 .Name = caller.Name,
146                 .Value = caller
147             }
148
149             For Each expr As UnaryExpression In arrayData
150                 Dim member = DirectCast(expr.Operand, MemberExpression)
151                 Dim constantExpression As ConstantExpression = DirectCast(member.Expression, ConstantExpression)
152                 Dim name As String = member.Member.Name.Replace("$VB$Local_""")
153                 Dim field As FieldInfo = DirectCast(member.Member, FieldInfo)
154                 Dim value As Object = field.GetValue(constantExpression.Value)
155
156                 out += New Value With {
157                     .Name = name,
158                     .Type = value.GetType,
159                     .Value = value,
160                     .Trace = trace
161                 }
162             Next
163
164             Return out
165         End Function
166     End Module
167 End Namespace