1 #Region "Microsoft.VisualBasic::7de3b38abe167002542f089ac0bcd767, Microsoft.VisualBasic.Core\Extensions\Reflection\Delegate\DelegateFactory.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 DelegateFactory
35     
36     '         Function: (+3 Overloads) Contructor, (+2 OverloadsDefaultContructor, DelegateIndexerGet, DelegateIndexerSet, (+2 OverloadsEventAccessor
37     '                   EventAccessorImpl, (+4 OverloadsEventAdd, EventAddImpl, EventHandlerFactory, (+4 OverloadsEventRemove
38     '                   EventRemoveImpl, (+3 Overloads) FieldGet, FieldGet2, (+3 Overloads) FieldSet, (+2 Overloads) FieldSetWithCast
39     '                   GetConstructorInfo, GetEventInfo, GetEventInfoAccessor, GetFieldInfo, GetFuncDelegateArguments
40     '                   GetFuncDelegateReturnType, GetIndexerPropertyInfo, GetMethodInfo, GetPropertyInfo, GetStaticFieldInfo
41     '                   GetStaticMethodInfo, GetStaticPropertyInfo, (+8 OverloadsIndexerGet, (+7 OverloadsIndexerSet, (+2 OverloadsInstanceGenericMethod
42     '                   InstanceGenericMethodVoid, (+9 OverloadsInstanceMethod, InstanceMethod2, InstanceMethodVoid, (+6 OverloadsPropertyGet
43     '                   PropertyGet2, (+4 OverloadsPropertySet, StaticEventAdd, (+3 OverloadsStaticFieldGet, StaticFieldGetExpr
44     '                   (+3 OverloadsStaticFieldSet, StaticGenericMethod, StaticGenericMethodVoid, (+12 OverloadsStaticMethod, StaticMethodVoid
45     '                   (+3 OverloadsStaticPropertyGet, StaticPropertyGet2, (+3 OverloadsStaticPropertySet
46     
47     
48     ' /********************************************************************************/
49
50 #End Region
51
52 Imports System.Collections.Generic
53 Imports System.Linq
54 Imports System.Linq.Expressions
55 Imports System.Reflection
56 Imports System.Runtime.CompilerServices
57
58 Namespace Emit.Delegates
59
60     Public Module DelegateFactory
61
62         Const AddAccessor As String = "add"
63         Const Item As String = "Item"
64         Const RemoveAccessor As String = "remove"
65
66         ReadOnly EventHandlerFactoryMethodInfo As MethodInfo = GetType(DelegateFactory).GetMethod("EventHandlerFactory")
67         ReadOnly EventsProxies As New Dictionary(Of WeakReference(Of Object), WeakReference(Of Object))()
68
69         Public Function Contructor(Of TDelegate As Class)() As TDelegate
70             Dim source = GetFuncDelegateReturnType(Of TDelegate)()
71             Dim ctrArgs = GetFuncDelegateArguments(Of TDelegate)()
72             Dim constructorInfo = GetConstructorInfo(source, ctrArgs)
73             If constructorInfo Is Nothing Then
74                 Return Nothing
75             End If
76             Dim parameters = ctrArgs.[Select](AddressOf Expression.Parameter).AsList()
77             Return TryCast(Expression.Lambda(Expression.[New](constructorInfo, parameters), parameters).Compile(), TDelegate)
78         End Function
79
80         <Extension>
81         Public Function Contructor(source As Type, ParamArray ctrArgs As Type()) As Func(Of Object(), Object)
82             Dim constructorInfo = GetConstructorInfo(source, ctrArgs)
83             If constructorInfo Is Nothing Then
84                 Return Nothing
85             End If
86             Dim argsArray = Expression.Parameter(GetType(Object()))
87             Dim paramsExpression = New Expression(ctrArgs.Length - 1) {}
88             For i As Integer = 0 To ctrArgs.Length - 1
89                 Dim argType = ctrArgs(i)
90                 paramsExpression(i) = Expression.Convert(Expression.ArrayIndex(argsArray, Expression.Constant(i)), argType)
91             Next
92             Dim returnExpression As Expression = Expression.[New](constructorInfo, paramsExpression)
93             If Not source.IsClass Then
94                 returnExpression = Expression.Convert(returnExpression, GetType(Object))
95             End If
96             Return DirectCast(Expression.Lambda(returnExpression, argsArray).Compile(), Func(Of Object(), Object))
97         End Function
98
99         <Extension>
100         Public Function Contructor(Of TDelegate As Class)(source As Type) As TDelegate
101             Dim ctrArgs = GetFuncDelegateArguments(Of TDelegate)()
102             Dim constructorInfo = GetConstructorInfo(source, ctrArgs)
103             If constructorInfo Is Nothing Then
104                 Return Nothing
105             End If
106             Dim parameters = ctrArgs.[Select](AddressOf Expression.Parameter).AsList()
107             Dim returnExpression As Expression = Expression.[New](constructorInfo, parameters)
108             If Not source.IsClass Then
109                 returnExpression = Expression.Convert(returnExpression, GetType(Object))
110             End If
111             Return TryCast(Expression.Lambda(returnExpression, parameters).Compile(), TDelegate)
112         End Function
113
114         Public Function DefaultContructor(Of TSource)() As Func(Of TSource)
115             Return Contructor(Of Func(Of TSource))()
116         End Function
117
118         <Extension>
119         Public Function DefaultContructor(type As Type) As Func(Of Object)
120             Return type.Contructor(Of Func(Of Object))()
121         End Function
122
123         Public Function DelegateIndexerGet(source As Type, returnType As Type, ParamArray indexTypes As Type()) As [Delegate]
124             Dim propertyInfo = GetIndexerPropertyInfo(source, returnType, indexTypes)
125             If propertyInfo.GetMethod Is Nothing Then
126                 Return Nothing
127             End If
128             Dim sourceObjectParam = Expression.Parameter(GetType(Object))
129             Dim paramsExpression = New ParameterExpression(indexTypes.Length - 1) {}
130             For i As Integer = 0 To indexTypes.Length - 1
131                 Dim indexType = indexTypes(i)
132                 paramsExpression(i) = Expression.Parameter(indexType)
133             Next
134             Return Expression.Lambda(Expression.[Call](Expression.Convert(sourceObjectParam, source), propertyInfo.GetMethod, paramsExpression), {sourceObjectParam}.Concat(paramsExpression)).Compile()
135         End Function
136
137         Public Function DelegateIndexerSet(source As Type, returnType As Type, ParamArray indexTypes As Type()) As [Delegate]
138             Dim propertyInfo = GetIndexerPropertyInfo(source, returnType, indexTypes)
139             If propertyInfo.SetMethod Is Nothing Then
140                 Return Nothing
141             End If
142             Dim sourceObjectParam = Expression.Parameter(GetType(Object))
143             Dim valueParam = Expression.Parameter(returnType)
144             Dim indexExpressions = New ParameterExpression(indexTypes.Length - 1) {}
145             For i As Integer = 0 To indexTypes.Length - 1
146                 Dim indexType = indexTypes(i)
147                 indexExpressions(i) = Expression.Parameter(indexType)
148             Next
149             Dim callArgs = indexExpressions.Concat({valueParam}).ToArray()
150             Dim paramsExpressions = {sourceObjectParam}.Concat(callArgs)
151             Return Expression.Lambda(Expression.[Call](Expression.Convert(sourceObjectParam, source), propertyInfo.SetMethod, callArgs), paramsExpressions).Compile()
152         End Function
153
154         Public Function EventAdd(Of TSource, TEventArgs)(eventName As StringAs Action(Of TSource, EventHandler(Of TEventArgs))
155             Return EventAccessor(Of TSource, TEventArgs)(eventName, AddAccessor)
156         End Function
157
158         <Extension>
159         Public Function EventAdd(Of TEventArgs)(source As Type, eventName As StringAs Action(Of ObjectEventHandler(Of TEventArgs))
160             Return EventAccessor(Of TEventArgs)(source, eventName, AddAccessor)
161         End Function
162
163         Public Function EventAdd(Of TSource)(eventName As StringAs Action(Of TSource, Action(Of TSource, Object))
164             Return GetType(TSource).EventAddImpl(Of Action(Of TSource, Action(Of TSource, Object)))(eventName)
165         End Function
166
167         <Extension>
168         Public Function EventAdd(source As Type, eventName As StringAs Action(Of Object, Action(Of ObjectObject))
169             Return source.EventAddImpl(Of Action(Of Object, Action(Of ObjectObject)))(eventName)
170         End Function
171
172         Public Function EventHandlerFactory(Of TEventArgs As Class, TSource)(handler As Object, isRemove As BooleanAs EventHandler(Of TEventArgs)
173             Dim newEventHandler As EventHandler(Of TEventArgs)
174             Dim haveKey = False
175             Dim kv = EventsProxies.FirstOrDefault(
176                 Function(k)
177                     Dim keyTarget As Object = Nothing
178                     k.Key.TryGetTarget(keyTarget)
179                     If Equals(keyTarget, handler) Then
180                         haveKey = True
181                         Return True
182                     End If
183                     Return False
184                 End Function)
185
186             If haveKey Then
187                 Dim fromCache As Object = Nothing
188                 EventsProxies(kv.Key).TryGetTarget(fromCache)
189                 newEventHandler = DirectCast(fromCache, EventHandler(Of TEventArgs))
190                 If isRemove Then
191                     EventsProxies.Remove(kv.Key)
192                     Return newEventHandler
193                 End If
194             End If
195
196             If Not isRemove Then
197                 Dim action = TryCast(handler, Action(Of TSource, Object))
198                 If action IsNot Nothing Then
199                     newEventHandler = Sub(s, a) action(DirectCast(s, TSource), a)
200                 Else
201                     newEventHandler = New EventHandler(Of TEventArgs)(AddressOf DirectCast(handler, Action(Of ObjectObject)).Invoke)
202                 End If
203                 EventsProxies(New WeakReference(Of Object)(handler)) = New WeakReference(Of Object)(newEventHandler)
204                 Return newEventHandler
205             End If
206
207             Return Nothing
208         End Function
209
210         <Extension>
211         Public Function EventRemove(Of TEventArgs)(source As Type, eventName As StringAs Action(Of ObjectEventHandler(Of TEventArgs))
212             Return EventAccessor(Of TEventArgs)(source, eventName, RemoveAccessor)
213         End Function
214
215         Public Function EventRemove(Of TSource, TEventArgs)(eventName As StringAs Action(Of TSource, EventHandler(Of TEventArgs))
216             Return EventAccessor(Of TSource, TEventArgs)(eventName, RemoveAccessor)
217         End Function
218
219         Public Function EventRemove(Of TSource)(eventName As StringAs Action(Of TSource, Action(Of TSource, Object))
220             Return GetType(TSource).EventRemoveImpl(Of Action(Of TSource, Action(Of TSource, Object)))(eventName)
221         End Function
222
223         <Extension>
224         Public Function EventRemove(source As Type, eventName As StringAs Action(Of Object, Action(Of ObjectObject))
225             Return source.EventRemoveImpl(Of Action(Of Object, Action(Of ObjectObject)))(eventName)
226         End Function
227
228         Public Function FieldGet(Of TSource, TField)(fieldName As StringAs Func(Of TSource, TField)
229             Dim source = GetType(TSource)
230             Dim d As Object = source.FieldGet(fieldName)
231             Return TryCast(d, Func(Of TSource, TField))
232         End Function
233
234         <Extension>
235         Public Function FieldGet(Of TField)(source As Type, fieldName As StringAs Func(Of Object, TField)
236             Return TryCast(source.FieldGet(fieldName), Func(Of Object, TField))
237         End Function
238
239         <Extension>
240         Public Function FieldGet(source As Type, fieldName As StringAs Func(Of ObjectObject)
241             Dim fieldInfo = GetFieldInfo(source, fieldName)
242             If fieldInfo IsNot Nothing Then
243                 Dim sourceParam = Expression.Parameter(GetType(Object))
244                 Dim returnExpression As Expression = Expression.Field(Expression.Convert(sourceParam, source), fieldInfo)
245                 If Not fieldInfo.FieldType.IsClass Then
246                     returnExpression = Expression.Convert(returnExpression, GetType(Object))
247                 End If
248                 Dim lambda = Expression.Lambda(returnExpression, sourceParam)
249                 Return DirectCast(lambda.Compile(), Func(Of ObjectObject))
250             End If
251             Return Nothing
252         End Function
253
254         <Obsolete>
255         <Extension>
256         Public Function FieldGet2(Of TField)(source As Type, fieldName As StringAs Func(Of Object, TField)
257             Dim fieldInfo = GetFieldInfo(source, fieldName)
258             If fieldInfo IsNot Nothing Then
259                 Dim sourceParam = Expression.Parameter(GetType(Object))
260                 Dim returnExpression As Expression = Expression.Field(Expression.Convert(sourceParam, source), fieldInfo)
261                 Dim lambda = Expression.Lambda(returnExpression, sourceParam)
262                 Return DirectCast(lambda.Compile(), Func(Of Object, TField))
263             End If
264             Return Nothing
265         End Function
266
267         <Extension>
268         Public Function FieldSet(Of TProperty)(source As Type, fieldName As StringAs Action(Of Object, TProperty)
269             Dim fieldInfo As FieldInfo = GetFieldInfo(source, fieldName)
270             If fieldInfo IsNot Nothing AndAlso Not fieldInfo.IsInitOnly Then
271                 Dim sourceParam = Expression.Parameter(GetType(Object))  ' args1 参数
272                 Dim valueParam = Expression.Parameter(GetType(TProperty)) ' args2 参数
273                 Dim target = Expression.Convert(sourceParam, source)  ' args1 As <source Type>
274                 Dim fieldRef = Expression.Field(target, fieldInfo)  ' args1.Field
275                 Dim setValue = Expression.Assign(fieldRef, valueParam) ' args1.Field = args2
276                 Dim delgType As Type = GetType(Action(Of Object, TProperty))
277                 Dim te = Expression.Lambda(delgType, setValue, sourceParam, valueParam)
278                 Return DirectCast(te.Compile(), Action(Of Object, TProperty))
279             End If
280             Return Nothing
281         End Function
282
283         Public Function FieldSet(Of TSource, TProperty)(fieldName As StringAs Action(Of TSource, TProperty)
284             Dim source = GetType(TSource)
285             Dim fieldInfo = GetFieldInfo(source, fieldName)
286             If fieldInfo IsNot Nothing AndAlso Not fieldInfo.IsInitOnly Then
287                 Dim sourceParam = Expression.Parameter(source)
288                 Dim valueParam = Expression.Parameter(GetType(TProperty))
289                 Dim te = Expression.Lambda(GetType(Action(Of TSource, TProperty)), Expression.Assign(Expression.Field(sourceParam, fieldInfo), valueParam), sourceParam, valueParam)
290                 Return DirectCast(te.Compile(), Action(Of TSource, TProperty))
291             End If
292             Return Nothing
293         End Function
294
295         <Extension>
296         Public Function FieldSet(source As Type, fieldName As StringAs Action(Of ObjectObject)
297             Dim fieldInfo = GetFieldInfo(source, fieldName)
298             If fieldInfo IsNot Nothing AndAlso Not fieldInfo.IsInitOnly Then
299                 Dim sourceParam = Expression.Parameter(GetType(Object))
300                 Dim valueParam = Expression.Parameter(GetType(Object))
301                 Dim convertedValueExpr = Expression.Convert(valueParam, fieldInfo.FieldType)
302                 Dim returnExpression As Expression = Expression.Assign(Expression.Field(Expression.Convert(sourceParam, source), fieldInfo), convertedValueExpr)
303                 If Not fieldInfo.FieldType.IsClass Then
304                     returnExpression = Expression.Convert(returnExpression, GetType(Object))
305                 End If
306                 Dim lambda = Expression.Lambda(GetType(Action(Of ObjectObject)), returnExpression, sourceParam, valueParam)
307                 Return DirectCast(lambda.Compile(), Action(Of ObjectObject))
308             End If
309             Return Nothing
310         End Function
311
312         <Obsolete>
313         <Extension>
314         Public Function FieldSetWithCast(Of TProperty)(source As Type, fieldName As StringAs Action(Of Object, TProperty)
315             Return TryCast(source.FieldSet(fieldName), Action(Of Object, TProperty))
316         End Function
317
318         <Obsolete>
319         Public Function FieldSetWithCast(Of TSource, TProperty)(fieldName As StringAs Action(Of TSource, TProperty)
320             Return TryCast(GetType(TSource).FieldSet(fieldName), Action(Of TSource, TProperty))
321         End Function
322
323         Public Function IndexerGet(Of TSource, TReturn, TIndex)() As Func(Of TSource, TIndex, TReturn)
324             Dim propertyInfo = GetIndexerPropertyInfo(GetType(TSource), GetType(TReturn), {GetType(TIndex)})
325             Return DirectCast(propertyInfo.GetMethod.CreateDelegate(GetType(Func(Of TSource, TIndex, TReturn))), Func(Of TSource, TIndex, TReturn))
326         End Function
327
328         Public Function IndexerGet(Of TSource, TReturn, TIndex, TIndex2)() As Func(Of TSource, TIndex, TIndex2, TReturn)
329             Dim propertyInfo = GetIndexerPropertyInfo(GetType(TSource), GetType(TReturn), {GetType(TIndex), GetType(TIndex2)})
330             Return DirectCast(propertyInfo.GetMethod.CreateDelegate(GetType(Func(Of TSource, TIndex, TIndex2, TReturn))), Func(Of TSource, TIndex, TIndex2, TReturn))
331         End Function
332
333         Public Function IndexerGet(Of TSource, TReturn, TIndex, TIndex2, TIndex3)() As Func(Of TSource, TIndex, TIndex2, TIndex2, TReturn)
334             Dim propertyInfo = GetIndexerPropertyInfo(GetType(TSource), GetType(TReturn), {GetType(TIndex), GetType(TIndex2), GetType(TIndex3)})
335             Return DirectCast(propertyInfo.GetMethod.CreateDelegate(GetType(Func(Of TSource, TIndex, TIndex2, TIndex2, TReturn))), Func(Of TSource, TIndex, TIndex2, TIndex2, TReturn))
336         End Function
337
338         <Extension>
339         Public Function IndexerGet(Of TReturn, TIndex)(source As Type) As Func(Of Object, TIndex, TReturn)
340             Dim indexType = GetType(TIndex)
341             Return DirectCast(DelegateIndexerGet(source, GetType(TReturn), indexType), Func(Of Object, TIndex, TReturn))
342         End Function
343
344         <Extension>
345         Public Function IndexerGet(Of TReturn, TIndex, TIndex2)(source As Type) As Func(Of Object, TIndex, TIndex2, TReturn)
346             Dim indexType = GetType(TIndex)
347             Dim indexType2 = GetType(TIndex2)
348             Return DirectCast(DelegateIndexerGet(source, GetType(TReturn), indexType, indexType2), Func(Of Object, TIndex, TIndex2, TReturn))
349         End Function
350
351         <Extension>
352         Public Function IndexerGet(Of TReturn, TIndex, TIndex2, TIndex3)(source As Type) As Func(Of Object, TIndex, TIndex2, TIndex3, TReturn)
353             Dim indexType = GetType(TIndex)
354             Dim indexType2 = GetType(TIndex2)
355             Dim indexType3 = GetType(TIndex3)
356             Return DirectCast(DelegateIndexerGet(source, GetType(TReturn), indexType, indexType2, indexType3), Func(Of Object, TIndex, TIndex2, TIndex3, TReturn))
357         End Function
358
359         <Extension>
360         Public Function IndexerGet(source As Type, returnType As Type, ParamArray indexTypes As Type()) As Func(Of ObjectObject(), Object)
361             Dim propertyInfo = GetIndexerPropertyInfo(source, returnType, indexTypes)
362             If propertyInfo.GetMethod Is Nothing Then
363                 Return Nothing
364             End If
365             Dim sourceObjectParam = Expression.Parameter(GetType(Object))
366             Dim indexesParam = Expression.Parameter(GetType(Object()))
367             Dim paramsExpression = New Expression(indexTypes.Length - 1) {}
368             For i As Integer = 0 To indexTypes.Length - 1
369                 Dim indexType = indexTypes(i)
370                 paramsExpression(i) = Expression.Convert(Expression.ArrayIndex(indexesParam, Expression.Constant(i)), indexType)
371             Next
372             Dim returnExpression As Expression = Expression.[Call](Expression.Convert(sourceObjectParam, source), propertyInfo.GetMethod, paramsExpression)
373             If Not propertyInfo.PropertyType.IsClass Then
374                 returnExpression = Expression.Convert(returnExpression, GetType(Object))
375             End If
376             Return DirectCast(Expression.Lambda(returnExpression, sourceObjectParam, indexesParam).Compile(), Func(Of ObjectObject(), Object))
377         End Function
378
379         <Extension>
380         Public Function IndexerGet(source As Type, returnType As Type, indexType As Type) As Func(Of ObjectObjectObject)
381             Dim propertyInfo = GetIndexerPropertyInfo(source, returnType, {indexType})
382             If propertyInfo.GetMethod Is Nothing Then
383                 Return Nothing
384             End If
385             Dim sourceObjectParam = Expression.Parameter(GetType(Object))
386             Dim indexObjectParam = Expression.Parameter(GetType(Object))
387             Dim returnExpression As Expression = Expression.[Call](Expression.Convert(sourceObjectParam, source), propertyInfo.GetMethod, Expression.Convert(indexObjectParam, indexType))
388             If Not propertyInfo.PropertyType.IsClass Then
389                 returnExpression = Expression.Convert(returnExpression, GetType(Object))
390             End If
391             Return DirectCast(Expression.Lambda(returnExpression, sourceObjectParam, indexObjectParam).Compile(), Func(Of ObjectObjectObject))
392         End Function
393
394         <Extension>
395         Public Function IndexerSet(Of TReturn, TIndex)(source As Type) As Action(Of Object, TIndex, TReturn)
396             Dim indexType = GetType(TIndex)
397             Return DirectCast(DelegateIndexerSet(source, GetType(TReturn), indexType), Action(Of Object, TIndex, TReturn))
398         End Function
399
400         <Extension>
401         Public Function IndexerSet(Of TReturn, TIndex, TIndex2)(source As Type) As Action(Of Object, TIndex, TIndex2, TReturn)
402             Dim indexType = GetType(TIndex)
403             Dim indexType2 = GetType(TIndex2)
404             Return DirectCast(DelegateIndexerSet(source, GetType(TReturn), indexType, indexType2), Action(Of Object, TIndex, TIndex2, TReturn))
405         End Function
406
407         <Extension>
408         Public Function IndexerSet(Of TReturn, TIndex, TIndex2, TIndex3)(source As Type) As Action(Of Object, TIndex, TIndex2, TIndex3, TReturn)
409             Dim indexType = GetType(TIndex)
410             Dim indexType2 = GetType(TIndex2)
411             Dim indexType3 = GetType(TIndex3)
412             Return DirectCast(DelegateIndexerSet(source, GetType(TReturn), indexType, indexType2, indexType3), Action(Of Object, TIndex, TIndex2, TIndex3, TReturn))
413         End Function
414
415         Public Function IndexerSet(Of TSource, TIndex, TProperty)() As Action(Of TSource, TIndex, TProperty)
416             Dim sourceType = GetType(TSource)
417             Dim propertyInfo = GetIndexerPropertyInfo(sourceType, GetType(TProperty), {GetType(TIndex)})
418             Return DirectCast(propertyInfo.SetMethod.CreateDelegate(GetType(Action(Of TSource, TIndex, TProperty))), Action(Of TSource, TIndex, TProperty))
419         End Function
420
421         Public Function IndexerSet(Of TSource, TReturn, TIndex, TIndex2)() As Action(Of TSource, TIndex, TIndex2, TReturn)
422             Dim propertyInfo = GetIndexerPropertyInfo(GetType(TSource), GetType(TReturn), {GetType(TIndex), GetType(TIndex2)})
423             Return DirectCast(propertyInfo.SetMethod.CreateDelegate(GetType(Action(Of TSource, TIndex, TIndex2, TReturn))), Action(Of TSource, TIndex, TIndex2, TReturn))
424         End Function
425
426         Public Function IndexerSet(Of TSource, TReturn, TIndex, TIndex2, TIndex3)() As Action(Of TSource, TIndex, TIndex2, TIndex2, TReturn)
427             Dim propertyInfo = GetIndexerPropertyInfo(GetType(TSource), GetType(TReturn), {GetType(TIndex), GetType(TIndex2), GetType(TIndex3)})
428             Return DirectCast(propertyInfo.SetMethod.CreateDelegate(GetType(Action(Of TSource, TIndex, TIndex2, TIndex2, TReturn))), Action(Of TSource, TIndex, TIndex2, TIndex2, TReturn))
429         End Function
430
431         <Extension>
432         Public Function IndexerSet(source As Type, returnType As Type, ParamArray indexTypes As Type()) As Action(Of ObjectObject(), Object)
433             Dim propertyInfo = GetIndexerPropertyInfo(source, returnType, indexTypes)
434             If propertyInfo.SetMethod Is Nothing Then
435                 Return Nothing
436             End If
437             Dim sourceObjectParam = Expression.Parameter(GetType(Object))
438             Dim indexesParam = Expression.Parameter(GetType(Object()))
439             Dim valueParam = Expression.Parameter(GetType(Object))
440             Dim paramsExpression = New Expression(indexTypes.Length) {}
441             For i As Integer = 0 To indexTypes.Length - 1
442                 Dim indexType = indexTypes(i)
443                 paramsExpression(i) = Expression.Convert(Expression.ArrayIndex(indexesParam, Expression.Constant(i)), indexType)
444             Next
445             paramsExpression(indexTypes.Length) = Expression.Convert(valueParam, returnType)
446             Dim returnExpression As Expression = Expression.[Call](Expression.Convert(sourceObjectParam, source), propertyInfo.SetMethod, paramsExpression)
447             Return DirectCast(Expression.Lambda(returnExpression, sourceObjectParam, indexesParam, valueParam).Compile(), Action(Of ObjectObject(), Object))
448         End Function
449
450         <Extension>
451         Public Function InstanceGenericMethod(source As Type, name As String, paramsTypes As Type(), typeParams As Type()) As Func(Of ObjectObject(), Object)
452             Return InstanceGenericMethod(Of Func(Of ObjectObject(), Object))(source, name, typeParams, paramsTypes)
453         End Function
454
455         <Extension>
456         Public Function InstanceGenericMethod(Of TDelegate As Class)(source As Type, name As String, typeParams As Type(), paramsTypes As Type()) As TDelegate
457             Dim methodInfo = GetMethodInfo(source, name, paramsTypes, typeParams)
458             If methodInfo Is Nothing Then
459                 Return Nothing
460             End If
461             Dim argsArray = Expression.Parameter(GetType(Object()))
462             Dim sourceParameter = Expression.Parameter(GetType(Object))
463             Dim paramsExpression = New Expression(paramsTypes.Length - 1) {}
464             For i As Integer = 0 To paramsTypes.Length - 1
465                 Dim argType = paramsTypes(i)
466                 paramsExpression(i) = Expression.Convert(Expression.ArrayIndex(argsArray, Expression.Constant(i)), argType)
467             Next
468             Dim returnExpression As Expression = Expression.[Call](Expression.Convert(sourceParameter, source), methodInfo, paramsExpression)
469             If methodInfo.ReturnType IsNot GetType(System.Void) AndAlso Not methodInfo.ReturnType.IsClass Then
470                 returnExpression = Expression.Convert(returnExpression, GetType(Object))
471             End If
472             Return TryCast(Expression.Lambda(returnExpression, sourceParameter, argsArray).Compile(), TDelegate)
473         End Function
474
475         <Extension>
476         Public Function InstanceGenericMethodVoid(source As Type, name As String, paramsTypes As Type(), typeParams As Type()) As Action(Of ObjectObject())
477             Return InstanceGenericMethod(Of Action(Of ObjectObject()))(source, name, typeParams, paramsTypes)
478         End Function
479
480         <Extension>
481         Public Function InstanceMethod(source As Type, name As StringParamArray paramsTypes As Type()) As Func(Of ObjectObject(), Object)
482             Return InstanceGenericMethod(Of Func(Of ObjectObject(), Object))(source, name, Nothing, paramsTypes)
483         End Function
484
485         Public Function InstanceMethod(Of TDelegate As Class, TParam1)(name As StringAs TDelegate
486             Return InstanceMethod(Of TDelegate)(name, GetType(TParam1))
487         End Function
488
489         Public Function InstanceMethod(Of TDelegate As Class, TParam1, TParam2)(name As StringAs TDelegate
490             Return InstanceMethod(Of TDelegate)(name, GetType(TParam1), GetType(TParam2))
491         End Function
492
493         Public Function InstanceMethod(Of TDelegate As Class, TParam1, TParam2, TParam3)(name As StringAs TDelegate
494             Return InstanceMethod(Of TDelegate)(name, GetType(TParam1), GetType(TParam2), GetType(TParam3))
495         End Function
496
497         Public Function InstanceMethod(Of TDelegate As Class)(name As StringParamArray typeParameters As Type()) As TDelegate
498             Dim paramsTypes = GetFuncDelegateArguments(Of TDelegate)()
499             Dim source = paramsTypes.First()
500             paramsTypes = paramsTypes.Skip(1).ToArray()
501             Dim methodInfo = GetMethodInfo(source, name, paramsTypes, typeParameters)
502             Return TryCast(methodInfo.CreateDelegate(GetType(TDelegate)), TDelegate)
503         End Function
504
505         <Extension>
506         Public Function InstanceMethod(Of TDelegate As Class, TParam1)(source As Type, name As StringAs TDelegate
507             Return source.InstanceMethod(Of TDelegate)(name, {GetType(TParam1)})
508         End Function
509
510         <Extension>
511         Public Function InstanceMethod(Of TDelegate As Class, TParam1, TParam2)(source As Type, name As StringAs TDelegate
512             Return source.InstanceMethod(Of TDelegate)(name, {GetType(TParam1), GetType(TParam2)})
513         End Function
514
515         <Extension>
516         Public Function InstanceMethod(Of TDelegate As Class, TParam1, TParam2, TParam3)(source As Type, name As StringAs TDelegate
517             Return source.InstanceMethod(Of TDelegate)(name, {GetType(TParam1), GetType(TParam2), GetType(TParam3)})
518         End Function
519
520         <Extension>
521         Public Function InstanceMethod(Of TDelegate As Class)(source As Type, name As StringOptional typeParams As Type() = NothingAs TDelegate
522             Dim delegateParams = GetFuncDelegateArguments(Of TDelegate)()
523             Dim instanceParam = delegateParams(0)
524             delegateParams = delegateParams.Skip(1).ToArray()
525             Dim methodInfo = GetMethodInfo(source, name, delegateParams, typeParams)
526             If methodInfo Is Nothing Then
527                 Return Nothing
528             End If
529             Dim deleg As [Delegate]
530             If instanceParam Is source Then
531                 deleg = methodInfo.CreateDelegate(GetType(TDelegate))
532             Else
533                 Dim sourceParameter = Expression.Parameter(GetType(Object))
534                 Dim expressions = delegateParams.[Select](AddressOf Expression.Parameter).ToArray()
535                 Dim returnExpression As Expression = Expression.[Call](Expression.Convert(sourceParameter, source), methodInfo, expressions.Cast(Of Expression)())
536                 If methodInfo.ReturnType IsNot GetType(System.Void) AndAlso Not methodInfo.ReturnType.IsClass Then
537                     returnExpression = Expression.Convert(returnExpression, GetType(Object))
538                 End If
539                 Dim lamdaParams = {sourceParameter}.Concat(expressions)
540                 deleg = Expression.Lambda(returnExpression, lamdaParams).Compile()
541             End If
542             Return TryCast(deleg, TDelegate)
543         End Function
544
545         Public Function InstanceMethod2(Of TDelegate As Class)(methodName As StringAs TDelegate
546             Dim source = GetType(TDelegate).GenericTypeArguments(0)
547             Dim param = Expression.Parameter(source)
548             Dim parameters = New List(Of ParameterExpression)() From {
549                 param
550             }
551             Dim params = GetFuncDelegateArguments(Of TDelegate)().Skip(1)
552             For Each type In params
553                 parameters.Add(Expression.Parameter(type))
554             Next
555             Dim te = Expression.Lambda(Expression.[Call](param, methodName, Nothing, parameters.Skip(1).Cast(Of Expression)().ToArray()), parameters)
556             Return TryCast(te.Compile(), TDelegate)
557         End Function
558
559         <Extension>
560         Public Function InstanceMethodVoid(source As Type, name As StringParamArray paramsTypes As Type()) As Action(Of ObjectObject())
561             Return InstanceGenericMethod(Of Action(Of ObjectObject()))(source, name, Nothing, paramsTypes)
562         End Function
563
564         <Extension>
565         Public Function PropertyGet(Of TProperty)(source As Type, propertyName As StringAs Func(Of Object, TProperty)
566             Return TryCast(source.PropertyGet(propertyName), Func(Of Object, TProperty))
567         End Function
568
569         <Extension>
570         Public Function PropertyGet(source As Type, propertyName As StringAs Func(Of ObjectObject)
571             Dim propertyInfo = GetPropertyInfo(source, propertyName)
572             If propertyInfo.GetMethod Is Nothing Then
573                 Return Nothing
574             Else
575                 Return source.PropertyGet(propertyInfo)
576             End If
577         End Function
578
579         <Extension>
580         Public Function PropertyGet(source As Type, [propertyInfo] As PropertyInfo) As Func(Of ObjectObject)
581             Dim sourceObjectParam = Expression.Parameter(GetType(Object))
582             Dim returnExpression As Expression = Expression.[Call](Expression.Convert(sourceObjectParam, source), propertyInfo.GetMethod)
583             If Not propertyInfo.PropertyType.IsClass Then
584                 returnExpression = Expression.Convert(returnExpression, GetType(Object))
585             End If
586             Return DirectCast(Expression.Lambda(returnExpression, sourceObjectParam).Compile(), Func(Of ObjectObject))
587         End Function
588
589         <Extension> Public Function PropertyGet(Of TSource, TProperty)(propertyInfo As PropertyInfo) As Func(Of TSource, TProperty)
590             Return PropertyGet(Of TSource, TProperty)(Nothing, propertyInfo)
591         End Function
592
593         Public Function PropertyGet(Of TSource, TProperty)(propertyName As StringAs Func(Of TSource, TProperty)
594             Return PropertyGet(Of TSource, TProperty)(propertyName, Nothing)
595         End Function
596
597         <Obsolete>
598         <Extension>
599         Public Function PropertyGet2(Of TSource, TProperty)(source As Type, propertyName As StringAs Func(Of TSource, TProperty)
600             Dim p = Expression.Parameter(source)
601             Dim te = Expression.Lambda(Expression.[Property](p, propertyName), p)
602             Return DirectCast(te.Compile(), Func(Of TSource, TProperty))
603         End Function
604
605         <Extension>
606         Public Function PropertySet(Of TSource, TProperty)(source As TSource, propertyName As StringAs Action(Of TSource, TProperty)
607             Return PropertySet(Of TSource, TProperty)(propertyName)
608         End Function
609
610         ''' <summary>
611         ''' 为指定类型的对象实例设置属性值,返回空值表名目标属性为一个只读属性或者写过程为私有访问类型
612         ''' </summary>
613         ''' <typeparam name="TProperty"></typeparam>
614         ''' <param name="source"></param>
615         ''' <param name="propertyName"></param>
616         ''' <returns></returns>
617         <Extension>
618         Public Function PropertySet(Of TProperty)(source As Type, propertyName As StringAs Action(Of Object, TProperty)
619             Dim propertyInfo = GetPropertyInfo(source, propertyName)
620             If propertyInfo.SetMethod Is Nothing Then
621                 Return Nothing
622             End If
623             Dim sourceObjectParam = Expression.Parameter(GetType(Object))
624             Dim propertyValueParam As ParameterExpression
625             Dim valueExpression As Expression
626             If propertyInfo.PropertyType Is GetType(TProperty) Then
627                 propertyValueParam = Expression.Parameter(propertyInfo.PropertyType)
628                 valueExpression = propertyValueParam
629             Else
630                 propertyValueParam = Expression.Parameter(GetType(TProperty))
631                 valueExpression = Expression.Convert(propertyValueParam, propertyInfo.PropertyType)
632             End If
633
634             Dim method = Expression.Lambda(
635                 Expression.[Call](
636                     Expression.Convert(sourceObjectParam, source),
637                     propertyInfo.SetMethod,
638                     valueExpression),
639                 sourceObjectParam,
640                 propertyValueParam).Compile()
641
642             Return DirectCast(method, Action(Of Object, TProperty))
643         End Function
644
645         <Extension>
646         Public Function PropertySet(source As Type, propertyName As StringAs Action(Of ObjectObject)
647             Return source.PropertySet(Of Object)(propertyName)
648         End Function
649
650         Public Function PropertySet(Of TSource, TProperty)(propertyName As StringAs Action(Of TSource, TProperty)
651             Dim source = GetType(TSource)
652             Dim propertyInfo = GetPropertyInfo(source, propertyName)
653             Return DirectCast(propertyInfo.SetMethod.CreateDelegate(GetType(Action(Of TSource, TProperty))), Action(Of TSource, TProperty))
654         End Function
655
656         <Extension>
657         Public Function StaticEventAdd(Of TEvent)(source As Type, eventName As StringAs Action(Of EventHandler(Of TEvent))
658             Dim eventInfo = source.GetEvent(eventName)
659             If eventInfo Is Nothing Then
660                 eventInfo = source.GetEvent(eventName, BindingFlags.NonPublic)
661             End If
662             If eventInfo Is Nothing Then
663                 eventInfo = source.GetEvent(eventName, BindingFlags.NonPublic Or BindingFlags.[Public])
664             End If
665             Return DirectCast(eventInfo.AddMethod.CreateDelegate(GetType(Action(Of EventHandler(Of TEvent)))), Action(Of EventHandler(Of TEvent)))
666         End Function
667
668         Public Function StaticFieldGet(Of TSource, TField)(fieldName As StringAs Func(Of TField)
669             Dim source = GetType(TSource)
670             Return source.StaticFieldGet(Of TField)(fieldName)
671         End Function
672
673         <Extension>
674         Public Function StaticFieldGet(Of TField)(source As Type, fieldName As StringAs Func(Of TField)
675             Dim fieldInfo = GetStaticFieldInfo(source, fieldName)
676             If fieldInfo IsNot Nothing Then
677                 Dim lambda = Expression.Lambda(Expression.Field(Nothing, fieldInfo))
678                 Return DirectCast(lambda.Compile(), Func(Of TField))
679             End If
680             Return Nothing
681         End Function
682
683         <Extension>
684         Public Function StaticFieldGet(source As Type, fieldName As StringAs Func(Of Object)
685             Dim fieldInfo = GetStaticFieldInfo(source, fieldName)
686             If fieldInfo IsNot Nothing Then
687                 Dim returnExpression As Expression = Expression.Field(Nothing, fieldInfo)
688                 If Not fieldInfo.FieldType.IsClass Then
689                     returnExpression = Expression.Convert(returnExpression, GetType(Object))
690                 End If
691                 Dim lambda = Expression.Lambda(returnExpression)
692                 Return DirectCast(lambda.Compile(), Func(Of Object))
693             End If
694             Return Nothing
695         End Function
696
697         <Obsolete>
698         Public Function StaticFieldGetExpr(Of TSource, TField)(fieldName As StringAs Func(Of TField)
699             Dim source = GetType(TSource)
700             Dim lambda = Expression.Lambda(Expression.Field(Nothing, source, fieldName))
701             Return DirectCast(lambda.Compile(), Func(Of TField))
702         End Function
703
704         Public Function StaticFieldSet(Of TSource, TField)(fieldName As StringAs Action(Of TField)
705             Dim source = GetType(TSource)
706             Return source.StaticFieldSet(Of TField)(fieldName)
707         End Function
708
709         <Extension>
710         Public Function StaticFieldSet(Of TField)(source As Type, fieldName As StringAs Action(Of TField)
711             Dim fieldInfo = GetStaticFieldInfo(source, fieldName)
712             If fieldInfo IsNot Nothing Then
713                 Dim valueParam = Expression.Parameter(GetType(TField))
714                 Dim lambda = Expression.Lambda(GetType(Action(Of TField)), Expression.Assign(Expression.Field(Nothing, fieldInfo), valueParam), valueParam)
715                 Return DirectCast(lambda.Compile(), Action(Of TField))
716             End If
717             Return Nothing
718         End Function
719
720         <Extension>
721         Public Function StaticFieldSet(source As Type, fieldName As StringAs Action(Of Object)
722             Dim fieldInfo = GetStaticFieldInfo(source, fieldName)
723             If fieldInfo IsNot Nothing AndAlso Not fieldInfo.IsInitOnly Then
724                 Dim valueParam = Expression.Parameter(GetType(Object))
725                 Dim convertedValueExpr = Expression.Convert(valueParam, fieldInfo.FieldType)
726                 Dim lambda = Expression.Lambda(GetType(Action(Of Object)), Expression.Assign(Expression.Field(Nothing, fieldInfo), convertedValueExpr), valueParam)
727                 Return DirectCast(lambda.Compile(), Action(Of Object))
728             End If
729             Return Nothing
730         End Function
731
732         <Extension>
733         Public Function StaticGenericMethod(source As Type, name As String, paramsTypes As Type(), typeParams As Type()) As Func(Of Object(), Object)
734             Return StaticMethod(Of Func(Of Object(), Object))(source, name, typeParams, paramsTypes)
735         End Function
736
737         <Extension>
738         Public Function StaticGenericMethodVoid(source As Type, name As String, paramsTypes As Type(), typeParams As Type()) As Action(Of Object())
739             Return StaticMethod(Of Action(Of Object()))(source, name, typeParams, paramsTypes)
740         End Function
741
742         Public Function StaticMethod(Of TSource, TDelegate As Class)(name As StringAs TDelegate
743             Return GetType(TSource).StaticMethod(Of TDelegate)(name)
744         End Function
745
746         Public Function StaticMethod(Of TSource, TDelegate As Class, TParam1)(name As StringAs TDelegate
747             Return GetType(TSource).StaticMethod(Of TDelegate)(name, GetType(TParam1))
748         End Function
749
750         Public Function StaticMethod(Of TSource, TDelegate As Class, TParam1, TParam2)(name As StringAs TDelegate
751             Return GetType(TSource).StaticMethod(Of TDelegate)(name, GetType(TParam1), GetType(TParam2))
752         End Function
753
754         Public Function StaticMethod(Of TSource, TDelegate As Class, TParam1, TParam2, TParam3)(name As StringAs TDelegate
755             Return GetType(TSource).StaticMethod(Of TDelegate)(name, GetType(TParam1), GetType(TParam2), GetType(TParam3))
756         End Function
757
758         Public Function StaticMethod(Of TSource, TDelegate As Class)(name As StringParamArray typeParameters As Type()) As TDelegate
759             Return GetType(TSource).StaticMethod(Of TDelegate)(name, typeParameters)
760         End Function
761
762         <Extension>
763         Public Function StaticMethod(Of TDelegate As Class, TParam1)(source As Type, name As StringAs TDelegate
764             Return source.StaticMethod(Of TDelegate)(name, GetType(TParam1))
765         End Function
766
767         <Extension>
768         Public Function StaticMethod(Of TDelegate As Class, TParam1, TParam2)(source As Type, name As StringAs TDelegate
769             Return source.StaticMethod(Of TDelegate)(name, GetType(TParam1), GetType(TParam2))
770         End Function
771
772         <Extension>
773         Public Function StaticMethod(Of TDelegate As Class, TParam1, TParam2, TParam3)(source As Type, name As StringAs TDelegate
774             Return source.StaticMethod(Of TDelegate)(name, GetType(TParam1), GetType(TParam2), GetType(TParam3))
775         End Function
776
777         <Extension>
778         Public Function StaticMethod(Of TDelegate As Class)(source As Type, name As StringParamArray typeParameters As Type()) As TDelegate
779             Dim paramsTypes = GetFuncDelegateArguments(Of TDelegate)()
780             Dim methodInfo = GetStaticMethodInfo(source, name, paramsTypes, typeParameters)
781             Return TryCast(methodInfo.CreateDelegate(GetType(TDelegate)), TDelegate)
782         End Function
783
784         <Extension>
785         Public Function StaticMethod(Of TDelegate As Class)(source As Type, name As StringAs TDelegate
786             Return source.StaticMethod(Of TDelegate)(name, Nothing)
787         End Function
788
789         <Extension>
790         Public Function StaticMethod(source As Type, name As StringParamArray paramsTypes As Type()) As Func(Of Object(), Object)
791             Return StaticMethod(Of Func(Of Object(), Object))(source, name, Nothing, paramsTypes)
792         End Function
793
794         <Extension>
795         Public Function StaticMethod(Of TDelegate As Class)(source As Type, name As String, typeParams As Type(), paramsTypes As Type()) As TDelegate
796             Dim methodInfo = GetStaticMethodInfo(source, name, paramsTypes, typeParams)
797             If methodInfo Is Nothing Then
798                 Return Nothing
799             End If
800             Dim argsArray = Expression.Parameter(GetType(Object()))
801             Dim paramsExpression = New Expression(paramsTypes.Length - 1) {}
802             For i As Integer = 0 To paramsTypes.Length - 1
803                 Dim argType = paramsTypes(i)
804                 paramsExpression(i) = Expression.Convert(Expression.ArrayIndex(argsArray, Expression.Constant(i)), argType)
805             Next
806             Dim returnExpression As Expression = Expression.[Call](methodInfo, paramsExpression)
807             If methodInfo.ReturnType IsNot GetType(System.Void) AndAlso Not methodInfo.ReturnType.IsClass Then
808                 returnExpression = Expression.Convert(returnExpression, GetType(Object))
809             End If
810             Return TryCast(Expression.Lambda(returnExpression, argsArray).Compile(), TDelegate)
811         End Function
812
813         <Extension>
814         Public Function StaticMethodVoid(source As Type, name As StringParamArray paramsTypes As Type()) As Action(Of Object())
815             Return StaticMethod(Of Action(Of Object()))(source, name, Nothing, paramsTypes)
816         End Function
817
818         Public Function StaticPropertyGet(Of TSource, TProperty)(propertyName As StringAs Func(Of TProperty)
819             Return GetType(TSource).StaticPropertyGet(Of TProperty)(propertyName)
820         End Function
821
822         <Extension>
823         Public Function StaticPropertyGet(Of TProperty)(source As Type, propertyName As StringAs Func(Of TProperty)
824             Dim propertyInfo = GetStaticPropertyInfo(source, propertyName)
825             Return DirectCast(propertyInfo.GetMethod.CreateDelegate(GetType(Func(Of TProperty))), Func(Of TProperty))
826         End Function
827
828         <Extension>
829         Public Function StaticPropertyGet(source As Type, propertyName As StringAs Func(Of Object)
830             Dim propertyInfo = GetStaticPropertyInfo(source, propertyName)
831             If propertyInfo.GetMethod Is Nothing Then
832                 Return Nothing
833             End If
834             Dim returnExpression As Expression = Expression.[Call](propertyInfo.GetMethod)
835             If Not propertyInfo.PropertyType.IsClass Then
836                 returnExpression = Expression.Convert(returnExpression, GetType(Object))
837             End If
838             Return DirectCast(Expression.Lambda(returnExpression).Compile(), Func(Of Object))
839         End Function
840
841         <Obsolete>
842         <Extension>
843         Public Function StaticPropertyGet2(Of TProperty)(source As Type, propertyName As StringAs Func(Of TProperty)
844             Dim te = Expression.Lambda(Expression.[Property](Nothing, source, propertyName))
845             Return DirectCast(te.Compile(), Func(Of TProperty))
846         End Function
847
848         Public Function StaticPropertySet(Of TSource, TProperty)(propertyName As StringAs Action(Of TProperty)
849             Return GetType(TSource).StaticPropertySet(Of TProperty)(propertyName)
850         End Function
851
852         <Extension>
853         Public Function StaticPropertySet(Of TProperty)(source As Type, propertyName As StringAs Action(Of TProperty)
854             Dim propertyInfo = GetStaticPropertyInfo(source, propertyName)
855             Return DirectCast(propertyInfo.SetMethod.CreateDelegate(GetType(Action(Of TProperty))), Action(Of TProperty))
856         End Function
857
858         <Extension>
859         Public Function StaticPropertySet(source As Type, propertyName As StringAs Action(Of Object)
860             Dim propertyInfo = GetStaticPropertyInfo(source, propertyName)
861             If propertyInfo.GetMethod Is Nothing Then
862                 Return Nothing
863             End If
864             Dim valueParam = Expression.Parameter(GetType(Object))
865             Dim convertedValue = Expression.Convert(valueParam, propertyInfo.PropertyType)
866             Dim returnExpression As Expression = Expression.[Call](propertyInfo.SetMethod, convertedValue)
867             If Not propertyInfo.PropertyType.IsClass Then
868                 returnExpression = Expression.Convert(returnExpression, GetType(Object))
869             End If
870             Return DirectCast(Expression.Lambda(returnExpression, valueParam).Compile(), Action(Of Object))
871         End Function
872
873         Private Function EventAccessor(Of TEventArgs)(source As Type, eventName As String, accessorName As StringAs Action(Of ObjectEventHandler(Of TEventArgs))
874             Dim accessor = GetEventInfoAccessor(eventName, source, accessorName)
875             If accessor IsNot Nothing Then
876                 Dim instanceParameter = Expression.Parameter(GetType(Object))
877                 Dim delegateTypeParameter = Expression.Parameter(GetType(EventHandler(Of TEventArgs)))
878                 Dim lambda = Expression.Lambda(Expression.[Call](Expression.Convert(instanceParameter, source), accessor, delegateTypeParameter), instanceParameter, delegateTypeParameter)
879                 Return DirectCast(lambda.Compile(), Action(Of ObjectEventHandler(Of TEventArgs)))
880             End If
881             Return Nothing
882         End Function
883
884         Private Function EventAccessor(Of TSource, TEventArgs)(eventName As String, accessorName As StringAs Action(Of TSource, EventHandler(Of TEventArgs))
885             Dim sourceType = GetType(TSource)
886             Dim accessor = GetEventInfoAccessor(eventName, sourceType, accessorName)
887             Return DirectCast(accessor.CreateDelegate(GetType(Action(Of TSource, EventHandler(Of TEventArgs)))), Action(Of TSource, EventHandler(Of TEventArgs)))
888         End Function
889
890         Private Function EventAccessorImpl(Of TDelegate As Class)(source As Type, eventName As String, accessorName As StringAs TDelegate
891             Dim eventInfo = GetEventInfo(eventName, source)
892             If eventInfo IsNot Nothing Then
893                 Dim accessor = If(accessorName = AddAccessor, eventInfo.AddMethod, eventInfo.RemoveMethod)
894                 Dim eventArgsType = eventInfo.EventHandlerType.GetGenericArguments()(0)
895                 Dim instanceParameter = Expression.Parameter(GetType(Object))
896                 Dim delegateTypeParameter = Expression.Parameter(GetType(Object))
897                 Dim methodCallExpression = Expression.[Call](EventHandlerFactoryMethodInfo.MakeGenericMethod(eventArgsType, source), delegateTypeParameter, Expression.Constant(accessorName = RemoveAccessor))
898                 Dim lambda = Expression.Lambda(Expression.[Call](Expression.Convert(instanceParameter, source), accessor, methodCallExpression), instanceParameter, delegateTypeParameter)
899                 Return TryCast(lambda.Compile(), TDelegate)
900             End If
901             Return Nothing
902         End Function
903
904         <Extension>
905         Private Function EventAddImpl(Of TDelegate As Class)(source As Type, eventName As StringAs TDelegate
906             Return EventAccessorImpl(Of TDelegate)(source, eventName, AddAccessor)
907         End Function
908
909         <Extension>
910         Private Function EventRemoveImpl(Of TDelegate As Class)(source As Type, eventName As StringAs TDelegate
911             Return EventAccessorImpl(Of TDelegate)(source, eventName, RemoveAccessor)
912         End Function
913
914         Private Function GetConstructorInfo(source As Type, types As Type()) As ConstructorInfo
915             Return If((If(source.GetConstructor(BindingFlags.[Public], Nothing, types, Nothing), source.GetConstructor(BindingFlags.NonPublic, Nothing, types, Nothing))), source.GetConstructor(BindingFlags.NonPublic Or BindingFlags.[Public] Or BindingFlags.Instance, Nothing, types, Nothing))
916         End Function
917
918         Private Function GetEventInfo(eventName As String, sourceType As Type) As EventInfo
919             Return If((If(sourceType.GetEvent(eventName), sourceType.GetEvent(eventName, BindingFlags.NonPublic))), sourceType.GetEvent(eventName, BindingFlags.NonPublic Or BindingFlags.[Public] Or BindingFlags.Instance))
920         End Function
921
922         Private Function GetEventInfoAccessor(eventName As String, sourceType As Type, accessor As StringAs MethodInfo
923             Dim eventInfo = GetEventInfo(eventName, sourceType)
924             Return If(accessor = AddAccessor, eventInfo.AddMethod, eventInfo.RemoveMethod)
925         End Function
926
927         Private Function GetFieldInfo(source As Type, fieldName As StringAs FieldInfo
928             Dim fieldInfo = If((If(source.GetField(fieldName), source.GetField(fieldName, BindingFlags.Instance Or BindingFlags.NonPublic))), source.GetField(fieldName, BindingFlags.Instance Or BindingFlags.NonPublic Or BindingFlags.[Public]))
929             Return fieldInfo
930         End Function
931
932         Private Function GetFuncDelegateArguments(Of TDelegate As Class)() As Type()
933             Dim arguments As IEnumerable(Of Type) = GetType(TDelegate).GenericTypeArguments
934             Return arguments.Reverse().Skip(1).Reverse().ToArray()
935         End Function
936
937         Private Function GetFuncDelegateReturnType(Of TDelegate As Class)() As Type
938             Return GetType(TDelegate).GenericTypeArguments.Last()
939         End Function
940
941         Private Function GetIndexerPropertyInfo(source As Type, returnType As Type, indexesTypes As Type(), Optional indexerName As String = NothingAs PropertyInfo
942             indexerName = If(indexerName, Item)
943
944             Dim propertyInfo = If((If(source.GetProperty(indexerName, returnType, indexesTypes), source.GetProperty(indexerName, BindingFlags.NonPublic, Nothing, returnType, indexesTypes, Nothing))), source.GetProperty(indexerName, BindingFlags.NonPublic Or BindingFlags.[Public] Or BindingFlags.Instance, Nothing, returnType, indexesTypes, Nothing))
945             If propertyInfo IsNot Nothing Then
946                 Return propertyInfo
947             End If
948             Dim indexer = source.GetProperties().FirstOrDefault(Function(p) p.GetIndexParameters().Length > 0)
949             Return If(indexer IsNot NothingGetIndexerPropertyInfo(source, returnType, indexesTypes, indexer.Name), Nothing)
950         End Function
951
952         Private Function GetMethodInfo(source As Type, name As String, parametersTypes As Type(), Optional typeParameters As Type() = NothingAs MethodInfo
953             Dim methodInfo As MethodInfo = Nothing
954             Try
955                 methodInfo = If((If(source.GetMethod(name, BindingFlags.Instance Or BindingFlags.[Public], Nothing, parametersTypes, Nothing), source.GetMethod(name, BindingFlags.Instance Or BindingFlags.NonPublic, Nothing, parametersTypes, Nothing))), source.GetMethod(name, BindingFlags.Instance Or BindingFlags.NonPublic Or BindingFlags.[Public], Nothing, parametersTypes, Nothing))
956                 'swallow and test generics
957             Catch generatedExceptionName As AmbiguousMatchException
958             End Try
959             'check for generic methods
960             If typeParameters IsNot Nothing Then
961                 Dim ms = source.GetMethods(BindingFlags.Instance Or BindingFlags.[Public]).Concat(source.GetMethods(BindingFlags.NonPublic Or BindingFlags.Instance)).Concat(source.GetMethods(BindingFlags.[Public] Or BindingFlags.NonPublic Or BindingFlags.Instance))
962                 For Each m In ms
963                     If m.Name = name AndAlso m.IsGenericMethod Then
964                         Dim parameters = m.GetParameters()
965                         Dim genericArguments = m.GetGenericArguments()
966                         Dim parametersTypesValid = parameters.Length = parametersTypes.Length
967                         parametersTypesValid = parametersTypesValid And genericArguments.Length = typeParameters.Length
968                         If Not parametersTypesValid Then
969                             Continue For
970                         End If
971                         For index As Integer = 0 To parameters.Length - 1
972                             Dim parameterInfo = parameters(index)
973                             Dim parameterType = parametersTypes(index)
974                             If parameterInfo.ParameterType IsNot parameterType AndAlso parameterInfo.ParameterType.IsGenericParameter AndAlso Not parameterInfo.ParameterType.CanBeAssignedFrom(parameterType) Then
975                                 parametersTypesValid = False
976                                 Exit For
977                             End If
978                         Next
979                         For index As Integer = 0 To genericArguments.Length - 1
980                             Dim genericArgument = genericArguments(index)
981                             Dim typeParameter = typeParameters(index)
982                             If Not genericArgument.CanBeAssignedFrom(typeParameter) Then
983                                 parametersTypesValid = False
984                                 Exit For
985                             End If
986                         Next
987                         If parametersTypesValid Then
988                             methodInfo = m.MakeGenericMethod(typeParameters)
989                             Exit For
990                         End If
991                     End If
992                 Next
993             End If
994             Return methodInfo
995         End Function
996
997         Private Function GetPropertyInfo(source As Type, propertyName As StringAs PropertyInfo
998             Dim propertyInfo = If(source.GetProperty(propertyName), If(source.GetProperty(propertyName, BindingFlags.NonPublic), source.GetProperty(propertyName, BindingFlags.NonPublic Or BindingFlags.[Public] Or BindingFlags.Instance)))
999             Return propertyInfo
1000         End Function
1001
1002         Private Function GetStaticFieldInfo(source As Type, fieldName As StringAs FieldInfo
1003             Dim fieldInfo = If((If(source.GetField(fieldName, BindingFlags.[Static]), source.GetField(fieldName, BindingFlags.[Static] Or BindingFlags.NonPublic))), source.GetField(fieldName, BindingFlags.[Static] Or BindingFlags.NonPublic Or BindingFlags.[Public]))
1004             Return fieldInfo
1005         End Function
1006
1007         Private Function GetStaticMethodInfo(source As Type, name As String, parametersTypes As Type(), Optional typeParameters As Type() = NothingAs MethodInfo
1008             Dim methodInfo As MethodInfo = Nothing
1009             Try
1010                 methodInfo = If((If(source.GetMethod(name, BindingFlags.[Static], Nothing, parametersTypes, Nothing), source.GetMethod(name, BindingFlags.[Static] Or BindingFlags.NonPublic, Nothing, parametersTypes, Nothing))), source.GetMethod(name, BindingFlags.[Static] Or BindingFlags.NonPublic Or BindingFlags.[Public], Nothing, parametersTypes, Nothing))
1011                 'swallow and test generics
1012             Catch generatedExceptionName As AmbiguousMatchException
1013             End Try
1014             'check for generic methods
1015             If typeParameters IsNot Nothing Then
1016                 Dim ms = source.GetMethods(BindingFlags.[Static]).Concat(source.GetMethods(BindingFlags.NonPublic Or BindingFlags.[Static])).Concat(source.GetMethods(BindingFlags.[Public] Or BindingFlags.NonPublic Or BindingFlags.[Static]))
1017                 For Each m In ms
1018                     If m.Name = name AndAlso m.IsGenericMethod Then
1019                         Dim parameters = m.GetParameters()
1020                         Dim genericArguments = m.GetGenericArguments()
1021                         Dim parametersTypesValid = parameters.Length = parametersTypes.Length
1022                         parametersTypesValid = parametersTypesValid And genericArguments.Length = typeParameters.Length
1023                         If Not parametersTypesValid Then
1024                             Continue For
1025                         End If
1026                         For index As Integer = 0 To parameters.Length - 1
1027                             Dim parameterInfo = parameters(index)
1028                             Dim parameterType = parametersTypes(index)
1029                             If parameterInfo.ParameterType IsNot parameterType AndAlso parameterInfo.ParameterType.IsGenericParameter AndAlso Not parameterInfo.ParameterType.CanBeAssignedFrom(parameterType) Then
1030                                 parametersTypesValid = False
1031                                 Exit For
1032                             End If
1033                         Next
1034                         For index As Integer = 0 To genericArguments.Length - 1
1035                             Dim genericArgument = genericArguments(index)
1036                             Dim typeParameter = typeParameters(index)
1037                             If Not genericArgument.CanBeAssignedFrom(typeParameter) Then
1038                                 parametersTypesValid = False
1039                                 Exit For
1040                             End If
1041                         Next
1042                         If parametersTypesValid Then
1043                             methodInfo = m.MakeGenericMethod(typeParameters)
1044                             Exit For
1045                         End If
1046                     End If
1047                 Next
1048             End If
1049             Return methodInfo
1050         End Function
1051
1052         Private Function GetStaticPropertyInfo(source As Type, propertyName As StringAs PropertyInfo
1053             Dim propertyInfo = If((If(source.GetProperty(propertyName, BindingFlags.[Static]), source.GetProperty(propertyName, BindingFlags.[Static] Or BindingFlags.NonPublic))), source.GetProperty(propertyName, BindingFlags.[Static] Or BindingFlags.NonPublic Or BindingFlags.[Public]))
1054             Return propertyInfo
1055         End Function
1056
1057         Private Function PropertyGet(Of TSource, TProperty)(Optional propertyName As String = NothingOptional propertyInfo As PropertyInfo = NothingAs Func(Of TSource, TProperty)
1058             Dim source = GetType(TSource)
1059             propertyInfo = If(propertyInfo, GetPropertyInfo(source, propertyName))
1060             Return DirectCast(propertyInfo.GetMethod.CreateDelegate(GetType(Func(Of TSource, TProperty))), Func(Of TSource, TProperty))
1061         End Function
1062     End Module
1063 End Namespace