Created
June 14, 2011 13:10
-
-
Save takeshik/1024863 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<Extension> _ | |
Public Class Dispatcher | |
' Methods | |
Public Shared Function DispatchMethod(ByVal instance As Expression, ByVal methods As IEnumerable(Of MethodInfo), ByVal typeArguments As IList(Of Type), ByVal arguments As IList(Of Expression)) As MethodCallExpression | |
Return (From t In (From m In methods Select New Candidate(instance, m, Nothing, arguments)).If(Of IEnumerable(Of Candidate))(_ => ((Not typeArguments Is Nothing) AndAlso typeArguments.Any(Of Type)()), DirectCast(s => (From _ In s | |
Where (_.Method.IsGenericMethodDefinition AndAlso (_.Method.GetGenericArguments.Length = typeArguments.Count)) | |
Select _.Method.MakeGenericMethod(typeArguments.ToArray(Of Type)()).Let(Of MethodInfo, Candidate)(m => New Candidate(_.Instance, m, m.GetGenericParameterMap(), arguments))), Func(Of IEnumerable(Of Candidate), IEnumerable(Of Candidate)))).Where(Of Candidate)(Function (ByVal t As Candidate) | |
Dim CS$<>8__locals27 As <>c__DisplayClass26 = DirectCast(Me, <>c__DisplayClass26) | |
Return IIf(Not IIf((Not instance Is Nothing), (Not t.Method.IsStatic OrElse t.Method.IsExtensionMethod()), t.Method.IsStatic), False, t.Method.GetParameters.If(Of ParameterInfo(), Boolean)(_ => t.Method.IsParamArrayMethod(), ps => (((t.Arguments.Count >= (ps.Length - 1)) AndAlso ps.SkipLast(Of ParameterInfo)(1).Zip(Of ParameterInfo, Expression, Boolean)(t.Arguments, (p, a) => Dispatcher.IsAppropriate(p.ParameterType, a.Type)).All(Of Boolean)(_ => _)) AndAlso EnumerableEx.Repeat(Of ParameterInfo)(ps.Last(Of ParameterInfo)()).Zip(Of ParameterInfo, Expression, Boolean)(t.Arguments.Skip(Of Expression)((ps.Length - 1)), (p, a) => Dispatcher.IsAppropriate(p.ParameterType.GetElementType, a.Type)).All(Of Boolean)(_ => _)), ps => ((CS$<>8__locals27.arguments.Count = ps.Length) AndAlso ps.Zip(Of ParameterInfo, Expression, Boolean)(CS$<>8__locals27.arguments, (p, a) => Dispatcher.IsAppropriate(p.ParameterType, a.Type)).All(Of Boolean)(_ => _)))) | |
End Function) | |
Select t.If(Of Candidate)(_ => _.Method.IsGenericMethod, DirectCast(_ => Dispatcher.InferTypeArguments((From p In t.Method.GetParameters Select p.ParameterType), (From e In t.Arguments Select e.Type)).Let(Of Dictionary(Of Type, Type), Candidate)(m => New Candidate(_.Instance, _.Method.MakeGenericMethod(m.Values.ToArray(Of Type)()), m, _.Arguments)), Func(Of Candidate, Candidate))).If(Of Candidate)(_ => _.Method.IsParamArrayMethod(), DirectCast(_ => _.Method.GetParameters.Let(Of ParameterInfo(), Candidate)(Function (ByVal ps As ParameterInfo()) | |
Dim CS$<>8__locals3e As <>c__DisplayClass3d = DirectCast(Me, <>c__DisplayClass3d) | |
Return ps.Last(Of ParameterInfo)().ParameterType.GetElementType.Let(Of Type, Candidate)(Function (ByVal et As Type) | |
Dim classd1 As <>c__DisplayClass3d = CS$<>8__locals3e | |
Return New Candidate(CS$<>8__locals3e._.Instance, CS$<>8__locals3e._.Method, CS$<>8__locals3e._.TypeArgumentMap, DirectCast(CS$<>8__locals3e._.Arguments.Take(Of Expression)((ps.Length - 1)).Concat(Of Expression)(EnumerableEx.Return(Of NewArrayExpression)(Expression.NewArrayInit(et, DirectCast((From e In CS$<>8__locals3e._.Arguments.Skip(Of Expression)((ps.Length - 1)) Select IIf((e.Type Is et), DirectCast(DirectCast(e, Func(Of Expression, Expression)), IEnumerable(Of Expression)), DirectCast(DirectCast(Expression.Convert(e, et), Func(Of Expression, Expression)), IEnumerable(Of Expression)))), IEnumerable(Of Expression))))).ToArray(Of Expression)(), IList(Of Expression))) | |
End Function) | |
End Function), Func(Of Candidate, Candidate))).If(Of Candidate)(_ => (_.Method.IsExtensionMethod() AndAlso (Not _.Instance Is Nothing)), DirectCast(_ => New Candidate(Nothing, _.Method, _.TypeArgumentMap, _.Arguments.StartWith(Of Expression)(_.Instance).ToArray(Of Expression)()), Func(Of Candidate, Candidate))) Into t | |
Order By t.Method.IsParamArrayMethod() | |
Order By t.Method.IsExtensionMethod() | |
Select t).ThenByDescending(Of Candidate, Integer)(t => t.TypeArgumentMap.Count).First(Of Candidate)().Let(Of Candidate, MethodCallExpression)(t => IIf((Not t.Instance Is Nothing), DirectCast(Expression.Call(t.Instance, t.Method, t.Arguments), Func(Of Candidate, MethodCallExpression)), DirectCast(Expression.Call(t.Method, t.Arguments), Func(Of Candidate, MethodCallExpression)))) | |
End Function | |
<Extension> _ | |
Public Shared Function GetConvertibleTypes(ByVal type As Type) As IEnumerable(Of Type) | |
Return EnumerableEx.Concat(Of Type)(New IEnumerable(Of Type)() { EnumerableEx.Generate(Of Type, Type)(type, t => (Not t Is Nothing), t => t.BaseType, _ => _), type.GetInterfaces, IIf(type.IsInterface, EnumerableEx.Return(Of Type)(GetType(Object)), Enumerable.Empty(Of Type)) }) | |
End Function | |
<Extension> _ | |
Public Shared Function GetExtensionMethods(ByVal type As Type) As IEnumerable(Of MethodInfo) | |
Return IIf(type.HasExtensionMethods(), type.GetMethods.Where(Of MethodInfo)(New Func(Of MethodInfo, Boolean)(AddressOf Dispatcher.IsExtensionMethod)), Enumerable.Empty(Of MethodInfo)) | |
End Function | |
<Extension> _ | |
Public Shared Function GetGenericParameterMap(ByVal method As MethodInfo) As Dictionary(Of Type, Type) | |
Return method.GetGenericMethodDefinition.GetGenericArguments.Zip(Of Type, Type, Tuple(Of Type, Type))(method.GetGenericArguments, New Func(Of Type, Type, Tuple(Of Type, Type))(AddressOf Tuple.Create(Of Type, Type))).ToDictionary(Of Tuple(Of Type, Type), Type, Type)(_ => _.Item1, _ => _.Item2) | |
End Function | |
<Extension> _ | |
Public Shared Function GetGenericParameterMap(ByVal type As Type) As Dictionary(Of Type, Type) | |
Return type.GetGenericTypeDefinition.GetGenericArguments.Zip(Of Type, Type, Tuple(Of Type, Type))(type.GetGenericArguments, New Func(Of Type, Type, Tuple(Of Type, Type))(AddressOf Tuple.Create(Of Type, Type))).ToDictionary(Of Tuple(Of Type, Type), Type, Type)(_ => _.Item1, _ => _.Item2) | |
End Function | |
<Extension> _ | |
Public Shared Function HasExtensionMethods(ByVal type As Type) As Boolean | |
Return Attribute.IsDefined(type, GetType(ExtensionAttribute)) | |
End Function | |
Public Shared Function InferTypeArguments(ByVal parameters As IEnumerable(Of Type), ByVal arguments As IEnumerable(Of Type)) As Dictionary(Of Type, Type) | |
Return (From _ In (From t In parameters | |
Where (t.IsGenericParameter OrElse t.IsGenericType) | |
Select t).Zip(Of Type, Type, IEnumerable(Of Tuple(Of Type, Type)))(arguments, (p, a) => IIf(p.IsGenericParameter, DirectCast(EnumerableEx.Return(Of Tuple(Of Type, Type))(Tuple.Create(Of Type, Type)(p, a)), Func(Of Type, Type, IEnumerable(Of Tuple(Of Type, Type)))), DirectCast(p.GetGenericArguments.Zip(Of Type, Type, Tuple(Of Type, Type))(a.GetConvertibleTypes().Single(Of Type)(t => (t.IsGenericType AndAlso (p.GetGenericTypeDefinition Is t.GetGenericTypeDefinition))).GetGenericArguments, New Func(Of Type, Type, Tuple(Of Type, Type))(AddressOf Tuple.Create(Of Type, Type))), Func(Of Type, Type, IEnumerable(Of Tuple(Of Type, Type)))))) Select _).Distinct(Of Tuple(Of Type, Type))().ToDictionary(Of Tuple(Of Type, Type), Type, Type)(_ => _.Item1, _ => _.Item2) | |
End Function | |
Public Shared Function IsAppropriate(ByVal parameter As Type, ByVal argument As Type) As Boolean | |
Return IIf(parameter.IsGenericParameter, argument.GetConvertibleTypes().Let(Of IEnumerable(Of Type), Boolean)(ts => parameter.GetGenericParameterConstraints.All(Of Type)(c => ts.Contains(Of Type)(c))), argument.GetConvertibleTypes().If(Of IEnumerable(Of Type))(_ => parameter.ContainsGenericParameters, DirectCast(_ => (From t In _ Select IIf(t.IsGenericType, DirectCast(DirectCast(t.GetGenericTypeDefinition, Func(Of Type, Type)), Func(Of IEnumerable(Of Type), IEnumerable(Of Type))), DirectCast(DirectCast(t, Func(Of Type, Type)), Func(Of IEnumerable(Of Type), IEnumerable(Of Type))))), Func(Of IEnumerable(Of Type), IEnumerable(Of Type)))).Let(Of IEnumerable(Of Type), Boolean)(_ => (_.Contains(Of Type)(parameter) OrElse (parameter.IsGenericType AndAlso _.Contains(Of Type)(parameter.GetGenericTypeDefinition))))) | |
End Function | |
<Extension> _ | |
Public Shared Function IsExtensionMethod(ByVal method As MethodInfo) As Boolean | |
Return Attribute.IsDefined(method, GetType(ExtensionAttribute)) | |
End Function | |
<Extension> _ | |
Public Shared Function IsParamArrayMethod(ByVal method As MethodBase) As Boolean | |
Return method.GetParameters.Let(Of ParameterInfo(), Boolean)(_ => (_.Any(Of ParameterInfo)() AndAlso Attribute.IsDefined(method.GetParameters.Last(Of ParameterInfo)(), GetType(ParamArrayAttribute)))) | |
End Function | |
' Nested Types | |
Friend Class Candidate | |
' Methods | |
Public Sub New(ByVal instance As Expression, ByVal member As MemberInfo, ByVal typeArgumentMap As IDictionary(Of Type, Type), ByVal arguments As IList(Of Expression)) | |
Me.Instance = instance | |
Me.Member = member | |
Me.TypeArgumentMap = IIf(typeArgumentMap <> Nothing , typeArgumentMap, New Dictionary(Of Type, Type)) | |
Me.Arguments = arguments | |
End Sub | |
' Properties | |
Property Arguments As IList(Of Expression) | |
Public Get | |
Private Set(ByVal value As IList(Of Expression)) | |
End Property | |
Public ReadOnly Property Field As FieldInfo | |
Get | |
Return TryCast(Me.Member,FieldInfo) | |
End Get | |
End Property | |
Property Instance As Expression | |
Public Get | |
Private Set(ByVal value As Expression) | |
End Property | |
Property Member As MemberInfo | |
Public Get | |
Private Set(ByVal value As MemberInfo) | |
End Property | |
Public ReadOnly Property Method As MethodInfo | |
Get | |
Return TryCast(Me.Member,MethodInfo) | |
End Get | |
End Property | |
Public ReadOnly Property [Property] As PropertyInfo | |
Get | |
Return TryCast(Me.Member,PropertyInfo) | |
End Get | |
End Property | |
Public ReadOnly Property Type As Type | |
Get | |
Return TryCast(Me.Member,Type) | |
End Get | |
End Property | |
Property TypeArgumentMap As IDictionary(Of Type, Type) | |
Public Get | |
Private Set(ByVal value As IDictionary(Of Type, Type)) | |
End Property | |
End Class | |
End Class |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment