Skip to content

Instantly share code, notes, and snippets.

@takeshik
Created June 14, 2011 13:10
Show Gist options
  • Save takeshik/1024863 to your computer and use it in GitHub Desktop.
Save takeshik/1024863 to your computer and use it in GitHub Desktop.
<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