Last active
September 23, 2020 06:27
-
-
Save Ringes/ff7d35dd39afc75e0abac24c74b55845 to your computer and use it in GitHub Desktop.
This code is a direct port into VB.Net of the Universal PredicateBuilder described here: https://petemontgomery.wordpress.com/2011/02/10/a-universal-predicatebuilder/
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
Imports System.Linq.Expressions | |
Public Module PredicateBuilder | |
'Private Sub New() | |
'End Sub | |
''' <summary> | |
''' Creates a predicate that evaluates to true | |
''' </summary> | |
Public Function [True](Of T)() As Expression(Of Func(Of T, Boolean)) | |
Return Function(f) True | |
End Function | |
''' <summary> | |
''' Creates a predicate that evaluates to false | |
''' </summary> | |
Public Function [False](Of T)() As Expression(Of Func(Of T, Boolean)) | |
Return Function(f) False | |
End Function | |
''' <summary> | |
''' Creates a predicate expression from the specified lambda expression | |
''' </summary> | |
Public Function Create(Of T)(predicate As Expression(Of Func(Of T, Boolean))) As Expression(Of Func(Of T, Boolean)) | |
Return predicate | |
End Function | |
''' <summary> | |
''' Combines the first predicate with the second using the logical "and". | |
''' </summary> | |
<System.Runtime.CompilerServices.Extension()> | |
Public Function [And](Of T)(ByVal first As Expression(Of Func(Of T, Boolean)), second As Expression(Of Func(Of T, Boolean))) As Expression(Of Func(Of T, Boolean)) | |
Return first.Compose(second, AddressOf Expression.And) | |
End Function | |
''' <summary> | |
''' Combines the first predicate with the second using the logical "or". | |
''' </summary> | |
<System.Runtime.CompilerServices.Extension()> | |
Public Function [Or](Of T)(ByVal first As Expression(Of Func(Of T, Boolean)), second As Expression(Of Func(Of T, Boolean))) As Expression(Of Func(Of T, Boolean)) | |
Return first.Compose(second, AddressOf Expression.Or) | |
End Function | |
''' <summary> | |
''' Negates the predicate. | |
''' </summary> | |
<System.Runtime.CompilerServices.Extension()> | |
Public Function [Not](Of T)(ByVal first As Expression(Of Func(Of T, Boolean))) As Expression(Of Func(Of T, Boolean)) | |
Dim negated = Expression.Not(first.Body) | |
Return Expression.Lambda(Of Func(Of T, Boolean))(negated, first.Parameters) | |
End Function | |
''' <summary> | |
''' Combines the first expression with the second using the specified merge function. | |
''' </summary> | |
<System.Runtime.CompilerServices.Extension()> | |
Public Function Compose(Of T)(ByVal first As Expression(Of T), second As Expression(Of T), merge As Func(Of Expression, Expression, Expression)) As Expression(Of T) | |
'zip parameters (map from parameters of second to parameters of first) | |
Dim map = first.Parameters _ | |
.Select(Function(f, i) New With {Key f, Key .s = second.Parameters(i)}) _ | |
.ToDictionary(Function(p) p.s, Function(p) p.f) | |
'replace parameters in the second lambda expression with the parameters in the first | |
Dim secondBody = ParameterRebinder.ReplaceParameters(map, second.Body) | |
'create a merged lambda expression with parameters from the first expression | |
Return Expression.Lambda(Of T)(merge(first.Body, secondBody), first.Parameters) | |
End Function | |
End Module | |
Class ParameterRebinder | |
Inherits ExpressionVisitor | |
ReadOnly _map As Dictionary(Of ParameterExpression, ParameterExpression) | |
Sub New(map As Dictionary(Of ParameterExpression, ParameterExpression)) | |
If map Is Nothing Then | |
_map = New Dictionary(Of ParameterExpression, ParameterExpression) | |
Else | |
_map = map | |
End If | |
End Sub | |
Public Shared Function ReplaceParameters(map As Dictionary(Of ParameterExpression, ParameterExpression), exp As Expression) As Expression | |
Return New ParameterRebinder(map).Visit(exp) | |
End Function | |
Protected Overrides Function VisitParameter(node As ParameterExpression) As Expression | |
Dim replacement As ParameterExpression | |
If _map.TryGetValue(node, replacement) Then | |
node = replacement | |
End If | |
Return MyBase.VisitParameter(node) | |
End Function | |
End Class |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment