Tag Archives: Fluent

Fluent Interface Helper (C#)

I’m practicing my C# so I thought I would take some of my most complex code and convert (most) of it by hand. In previous posts I explored how to make a fluent interface. I had to use lambdas, delegates and a whole lot of custom generics. It was a lot of fun. Here is how to use it in C# and a link to browse the code.

Let’s imagine that you have a collection of people.

List People = new List 
{
    new Person(){ name="Bentley", birthDate=new DateTime(1963, 3, 7)},
    new Person(){ name="Christy", birthDate=new DateTime(1973, 9, 19)},
    new Person(){ name="Benjamin", birthDate=new DateTime(2001, 9, 19)}
};

And let’s Imagine that you wanted to get a list of the people who’s name begins with the letter B and were borne sine 2000. You might do the following:

IEnumerable q = People.Where(p => p.name.StartsWith("B")).Where(p => p.birthDate > new DateTime(2000, 1, 1));

Which certainly gets the job done.

Now imagine that you are responsible for creating an maintaining a large list of business rules that look like this. Oh, and we might have some business analysts write the rules to help you out. Suddenly all the p => gets in the way of readability and sharing the task with less technical people.

One solution is a fluent interface. It’s a little more readable. Here is the same query done fluently.

PersonList q = People.Name().StartsWith("B").BirthDate().Greater(new DateTime(2000,1,1));

What do you think? Is it worth adding some extra code to clean up the text?

You can browse all the code or get a copy with Subversion at: svn checkout https://bentleys-code-samples.googlecode.com/svn/samples/FluentHelper FluentHelper

Updateable Fluent Collection

In my previous posts about my Adventures in Creating Fluent Interfaces I created a way to fluently filter objects in a collection by the methods of the object. That’s all nice and dandy but what is it worth if you can’t manipulate the objects in the same way. I want to be able to change the object also. My first goal is to just manipulate the properties on the object and not yet children objects. When I began I just started with an ‘Update’ method on the FluentComparableList object which was the object I returned when I selected PeopleList.Name which gave me all the filtering methods like greater and contains.

The Design Problem – invalid options

While writing out my tests (Not quite TDD but I did them really soon) I realized that this created issues. If I had a read only property I didn’t want the Set method to appear in the list because It would not work. I it’s a write only parameter then I didn’t want all the filtering methods available because there is no data to filter on. I noticed this when I wrote People.Name.IndexOf(“e”)… the ‘Set’ option came up. What would that be setting. I can’t set the index of the letter ‘e’! Am I setting the name before it? It’s unclear syntax. I decided I needed a separate object for updating than filtering.

First Solution – differentiate by additional options

This posed another issue because there are many cases where a method can both be updated and filtered. If it can be written to and read from I should be able to Update and Filter it. You can’t inherit from two objects (not in VB at least) so I had a quandary. I built out an example where I chose which to do in the syntax. For example: PeopleList.Name.Filter.Contains(“e”) but that lengthened the syntax. No, there had to be a better way.

Second Solution – Composition objects

My current solution is to create one object for update and another object for filtering and a third object that composes these together. It is a lot of complicated code but, once again, this code is in a library and should not change often. That is where the complexity can be managed. There is probably something better. I look forward to your suggestions.

When I type PersonList.Name I will receive a special string collection I call FluentStringCollection that has all the update and filter methods. When I type Personlist.Name.indexof(‘e’) I don’t have to return a collection that has all the update methods. i can just return a collection with just the filter methods. Separating it out also makes the code easier to follow and helps get closer to the single responsibility principal.

The Code

To get this done we will need more classes. I have the FluentComparableList from the last post but I renamed it to FluentCollectionFilter. I’m constantly trying to have the name make the most sense until I come to a release point. It remains mostly unchanged. Here it is so you can see where the other classes fit in.

Public Class FluentCollectionFilter(Of CollectionType As {ICollection, New}, ItemType, ParamaterType As IComparable)
    Public InternalList As CollectionType
    Public InternalFunction As Func(Of ItemType, ParamaterType)
    Public useNot As Boolean

    Sub New(ByRef list As CollectionType, ByVal _Func As Func(Of ItemType, ParamaterType), Optional ByVal _Not As Boolean = False)
        InternalList = list
        InternalFunction = _Func
        useNot = _Not
    End Sub

    Public Function [Not]() As FluentCollectionFilter(Of CollectionType, ItemType, ParamaterType)
        Return New FluentCollectionFilter(Of CollectionType, ItemType, ParamaterType)(InternalList, Function(s) InternalFunction(s), True)
    End Function

    Public Function GetNewList(ByRef _Func As Func(Of ItemType, Boolean))
        GetNewList = New CollectionType
        For Each item In InternalList
            If useNot Then
                If Not _Func(item) Then GetNewList.Add(item)
            Else
                If _Func(item) Then GetNewList.Add(item)
            End If
        Next
    End Function

    Public Function Greater(ByVal value As ParamaterType) As CollectionType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(value) > 0)
    End Function

    Public Function Lesser(ByVal value As ParamaterType) As CollectionType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(value) < 0)
    End Function

    Public Function LesserOrEqual(ByVal value As ParamaterType) As CollectionType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(value) <= 0)
    End Function

    Public Function GreaterOrEqual(ByVal value As ParamaterType) As CollectionType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(value) >= 0)
    End Function

    Public Function Between(ByVal Min As ParamaterType, ByVal Max As ParamaterType) As CollectionType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(Min) >= 0 And InternalFunction(item).CompareTo(Min) <= 0)
    End Function

    Public Shadows Function Equals(ByVal value As ParamaterType) As CollectionType
        Return GetNewList(Function(item) InternalFunction(item).Equals(value))
    End Function

End Class

To that we add our FluentCollectionSetter. You guessed it, this is the class that has all the methods for updating the objects in a collection. Right now there is only one which is Set. I’m still playing with the names. ‘Set’ is shorter than ‘Update’ but it is a reserved word. You will notice that there is also a new function InternalSetter. This is where we pass in the a function to update the parameter. A function to read a parameter is significantly different from a function to write so I needed to pass in a pointer to what function updates the proper parameter. More on that later.

Public Delegate Sub Setter(Of ItemType, ParamaterType)(ByRef item As ItemType, ByVal value As ParamaterType)

Public Class FluentCollectionSet(Of CollectionType As {ICollection, New}, ItemType, ParamaterType As IComparable)
    Public InternalList As CollectionType
    Public InternalFunction As Func(Of ItemType, ParamaterType)
    Public InternalSetter As Setter(Of ItemType, ParamaterType)


    Sub New(ByRef list As CollectionType, ByVal _Func As Func(Of ItemType, ParamaterType), ByRef _Setter As Setter(Of ItemType, ParamaterType))
        InternalList = list
        InternalFunction = _Func
        InternalSetter = _Setter
    End Sub

    Function [Set](ByVal Value As ParamaterType) As CollectionType
        For Each item In InternalList
            InternalSetter(item, Value)
        Next
        Return InternalList
    End Function
End Class

Now we need a third class that combines the FluentCollectionFilter and the FluentCollectionSetter. I could not inherit from two objects so I composed them together by setting up every method and wiring up the calls. Usually you could just inherit the methods and your class is much more concise. Here is the combined class:

Public Class FluentCollection(Of CollectionType As {ICollection, New}, ItemType, ParamaterType As IComparable)
    Public InternalList As CollectionType
    Public InternalFunction As Func(Of ItemType, ParamaterType)
    Public useNot As Boolean
    Public InternalSetter As Setter(Of ItemType, ParamaterType)

    Sub New(ByRef list As CollectionType, ByVal _Func As Func(Of ItemType, ParamaterType), ByRef _Setter As Setter(Of ItemType, ParamaterType), Optional ByVal _Not As Boolean = False)
        InternalList = list
        InternalFunction = _Func
        InternalSetter = _Setter
        useNot = _Not
    End Sub

    Public Function GetNewList(ByRef _Func As Func(Of ItemType, Boolean))
        Return New FluentCollectionFilter(Of CollectionType, ItemType, ParamaterType)(InternalList, InternalFunction, useNot). _
        GetNewList(_Func)
    End Function


    Public Function [Set](ByVal value As ParamaterType) As CollectionType
        Return New FluentCollectionSet(Of CollectionType, ItemType, ParamaterType)(InternalList, InternalFunction, InternalSetter). _
        Set(value)
    End Function

    Public Function Greater(ByVal value As ParamaterType) As CollectionType
        Return New FluentCollectionFilter(Of CollectionType, ItemType, ParamaterType)(InternalList, InternalFunction, useNot). _
        Greater(value)
    End Function

    Public Function Lesser(ByVal value As ParamaterType) As CollectionType
        Return New FluentCollectionFilter(Of CollectionType, ItemType, ParamaterType)(InternalList, InternalFunction, useNot). _
        Lesser(value)
    End Function

    Public Function LesserOrEqual(ByVal value As ParamaterType) As CollectionType
        Return New FluentCollectionFilter(Of CollectionType, ItemType, ParamaterType)(InternalList, InternalFunction, useNot). _
        LesserOrEqual(value)
    End Function

    Public Function GreaterOrEqual(ByVal value As ParamaterType) As CollectionType
        Return New FluentCollectionFilter(Of CollectionType, ItemType, ParamaterType)(InternalList, InternalFunction, useNot). _
        GreaterOrEqual(value)
    End Function

    Public Function Between(ByVal Min As ParamaterType, ByVal Max As ParamaterType) As CollectionType
        Return New FluentCollectionFilter(Of CollectionType, ItemType, ParamaterType)(InternalList, InternalFunction, useNot). _
        Between(Min, Max)
    End Function

    Public Shadows Function Equals(ByVal value As ParamaterType) As CollectionType
        Return New FluentCollectionFilter(Of CollectionType, ItemType, ParamaterType)(InternalList, InternalFunction, useNot). _
        Equals(value)
    End Function
End Class

One More class to inherit from the FluentCollection above to add on the special String only filter and updates. I just inherited as it works for what I am doing now and is significantly concise.

Public Class FluentCollectionString(Of CollectionType As {ICollection, New}, ItemType)
    Inherits FluentCollection(Of CollectionType, ItemType, String)

    Sub New(ByRef list As CollectionType, ByVal _Func As Func(Of ItemType, String), ByRef _Setter As Setter(Of ItemType, String), Optional ByVal _Not As Boolean = False)
        MyBase.New(list, _Func, _Setter, _Not)
    End Sub

    Public Shadows Function [Not]() As FluentCollectionString(Of CollectionType, ItemType)
        Return New FluentCollectionString(Of CollectionType, ItemType) _
        (InternalList, Function(s) InternalFunction(s), InternalSetter, True)
    End Function

    Public Function StartsWith(ByVal value As String) As CollectionType
        Return GetNewList(Function(item) InternalFunction(item).StartsWith(value))
    End Function

    Public Function EndsWith(ByVal value As String) As CollectionType
        Return GetNewList(Function(item) InternalFunction(item).EndsWith(value))
    End Function

    Public Function Contains(ByVal value As String) As CollectionType
        Return GetNewList(Function(item) InternalFunction(item).Contains(value))
    End Function

    Public Function IndexOf(ByVal value As String) As FluentCollectionFilter(Of CollectionType, ItemType, Integer)
        Return New FluentCollectionFilter(Of CollectionType, ItemType, Integer) _
        (InternalList, Function(s) InternalFunction(s).IndexOf(value))
    End Function

    Public Function Replace(ByVal oldValue As String, ByVal newValue As String) As CollectionType
        For Each item In InternalList
            Me.InternalSetter(item, InternalFunction(item).Replace(oldValue, newValue))
        Next
        Return InternalList
    End Function

As it turns out I could not figure out how to update items inside a function statement or a lambda. I tried several options including setting everything to ByRef but there is no ByRef on the function itself. The MSDN documentation implies that both of these are always read only. To be able to modify an item in a function I create a delegate and set it to the address of a function that sets the parameter. This adds several lines of code to each Parameter which you will see below. You will see that in the code below for the implementation of the new PersonList Class. This code is different from above in that it is not in the Fluent library. This is what your code would look like when using the library. It could be generated though as it is mostly just hooking things up.

Public Class PersonList
    Inherits List(Of Person)

    Sub New()
        MyBase.new()
    End Sub

    Sub New(ByVal List As List(Of Person))
        MyBase.New(List)
    End Sub

    Public Function Name() As FluentCollectionString(Of PersonList, Person)
        Return New FluentCollectionString(Of PersonList, Person)(Me, Function(s) s.Name, AddressOf NameSetter)
    End Function

    Private Sub NameSetter(ByRef si As Person, ByVal value As String)
        si.Name = value
    End Sub

    Public Function BirthDate() As FluentCollection(Of PersonList, Person, Date)
        Return New FluentCollection(Of PersonList, Person, Date) _
        (Me, Function(s) s.BirthDate, AddressOf BirthDateSetter)
    End Function

    Public Function BirthDate(ByVal value As Date) As PersonList
        Return New FluentCollection(Of PersonList, Person, Date) _
        (Me, Function(s) s.BirthDate, AddressOf BirthDateSetter). _
        Set(value)
    End Function

    Private Sub BirthDateSetter(ByRef si As Person, ByVal value As String)
        si.BirthDate = value
    End Sub
End Class

It’s starting to get quite complicated but if it can be code generated then it won’t be too bad. If it could be generated then you could just build your Person class and generate the collection to use the library and voila! lots of power with little work. The FluentCollectionString might also be generated and not be in the library. I’ll have to think about that more.

Now we can update our collected objects in the same line we filter them. We could change all the letter ‘e’ to the letter ‘a’ in everyone’s name borne after 1980 with just:

People.BirthDate.Greater(“1/1/1980”).Name.Replace(‘e’,’a’)

Now that’s power! Tell me what you think.

Fluent Collection NOT !

The title of this post might be a little misleading. I am still having Adventures in Creating Fluent Interfaces. I wanted to be able to find People with Names that did NOT Contain some text. I started of by adding a new function NotContains but I quickly realized that I would be doubling my functions. The answer was so simple and felt so good. I had already centralized by code that evaluated the function so I just needed to add an optional parameter boolean for tracking if I wanted the standard function or the ‘Not’ version. I added a variable to hold it. I modified the GetList function to use the new variable. Finally I created a new “Not’ function that returns the same FluentComparableList but passes in the boolean as true. Here is the modified FluentComparableList code sample:

 

Public Class FluentComparableList(Of ListType As {IList, New}, ItemType, ParamaterType As IComparable)
    Public InternalList As ListType
    Public InternalFunction As Func(Of ItemType, ParamaterType)
    Public useNot As Boolean


    Sub New(ByRef list As ListType, ByVal _Func As Func(Of ItemType, ParamaterType), Optional ByVal _Not As Boolean = False)
        InternalList = list
        InternalFunction = _Func
        useNot = _Not
    End Sub

    Public Function [Not]() As FluentComparableList(Of ListType, ItemType, ParamaterType)
        Return New FluentComparableList(Of ListType, ItemType, ParamaterType)(InternalList, Function(s) InternalFunction(s), True)
    End Function

    Public Function GetNewList(ByRef _Func As Func(Of ItemType, Boolean))
        GetNewList = New ListType
        For Each item In InternalList
            If useNot Then
                If Not _Func(item) Then GetNewList.Add(item)
            Else
                If _Func(item) Then GetNewList.Add(item)
            End If
        Next
    End Function

    Public Function Greater(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) > 0)
    End Function

    Public Function Lesser(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) < 0)
    End Function
etc..

I do even fewer changes to the FluentStringList. I just pass the boolean on to the base class. I have to shadow the Not class in the base class because I want to return a FluentStringList instead of the FluentStringList that comes out of the base. Now I have the ability to ‘Not’ everything. I can find out how many people don’t have ‘tle’ in their name with:

People.Name.Not.Contains('tle').count

Here are some tests:

Dim target As PersonList

Public Sub MyTestInitialize()
    target = New PersonList
    target.Add(New Person("Bentley", "1/1/1973"))
    target.Add(New Person("Joe", "2/1/1992"))
    target.Add(New Person("Jimmy", "3/1/2005"))
    target.Add(New Person("Karla", "4/1/1984"))
    target.Add(New Person("Cameron", "5/1/1950"))
End Sub


Public Sub FindAll_not_StartsWith()
    Dim Found = target.Name.Not.StartsWith("J")

    Assert.AreEqual(3, Found.Count)
    Assert.AreEqual(5, target.Count, "Has no side-effects")
End Sub


Public Sub BigTest()
    Dim Found = target.Name.Not.EndsWith("y").Name.Not.IndexOf("e").Not.Greater(1)

    Assert.AreEqual(1, Found.Count)
    'Only Karla should match this one
End Sub

I wouldn’t suggest using that many ‘Not’s in production code. It’s amazing how much power we got from so little code. Tell me what you think of this modification in the comments below.

The title of this post might be a little misleading. I am still having Adventures in Creating Fluent Interfaces. I wanted to be able to find People with Names that did NOT Contain some text. I started of by adding a new function NotContains but I quickly realized that I would be doubling my functions. The answer was so simple and felt so good. I had already centralized by code that evaluated the function so I just needed to add an optional parameter boolean for tracking if I wanted the standard function or the ‘Not’ version. I added a variable to hold it. I modified the GetList function to use the new variable. Finally I created a new “Not’ function that returns the same FluentComparableList but passes in the boolean as true. Here is the modified FluentComparableList code sample:

 

Public Class FluentComparableList(Of ListType As {IList, New}, ItemType, ParamaterType As IComparable)
    Public InternalList As ListType
    Public InternalFunction As Func(Of ItemType, ParamaterType)
    Public useNot As Boolean


    Sub New(ByRef list As ListType, ByVal _Func As Func(Of ItemType, ParamaterType), Optional ByVal _Not As Boolean = False)
        InternalList = list
        InternalFunction = _Func
        useNot = _Not
    End Sub

    Public Function [Not]() As FluentComparableList(Of ListType, ItemType, ParamaterType)
        Return New FluentComparableList(Of ListType, ItemType, ParamaterType)(InternalList, Function(s) InternalFunction(s), True)
    End Function

    Public Function GetNewList(ByRef _Func As Func(Of ItemType, Boolean))
        GetNewList = New ListType
        For Each item In InternalList
            If useNot Then
                If Not _Func(item) Then GetNewList.Add(item)
            Else
                If _Func(item) Then GetNewList.Add(item)
            End If
        Next
    End Function

    Public Function Greater(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) > 0)
    End Function

    Public Function Lesser(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) < 0)
    End Function
etc..

I do even fewer changes to the FluentStringList. I just pass the boolean on to the base class. I have to shadow the Not class in the base class because I want to return a FluentStringList instead of the FluentStringList that comes out of the base. Now I have the ability to ‘Not’ everything. I can find out how many people don’t have ‘tle’ in their name with:

People.Name.Not.Contains('tle').count

Here are some tests:

Dim target As PersonList

Public Sub MyTestInitialize()
    target = New PersonList
    target.Add(New Person("Bentley", "1/1/1973"))
    target.Add(New Person("Joe", "2/1/1992"))
    target.Add(New Person("Jimmy", "3/1/2005"))
    target.Add(New Person("Karla", "4/1/1984"))
    target.Add(New Person("Cameron", "5/1/1950"))
End Sub


Public Sub FindAll_not_StartsWith()
    Dim Found = target.Name.Not.StartsWith("J")

    Assert.AreEqual(3, Found.Count)
    Assert.AreEqual(5, target.Count, "Has no side-effects")
End Sub


Public Sub BigTest()
    Dim Found = target.Name.Not.EndsWith("y").Name.Not.IndexOf("e").Not.Greater(1)

    Assert.AreEqual(1, Found.Count)
    'Only Karla should match this one
End Sub

I wouldn’t suggest using that many ‘Not’s in production code. It’s amazing how much power we got from so little code. Tell me what you think of this modification in the comments below.

The title of this post might be a little misleading. I am still having Adventures in Creating Fluent Interfaces. I wanted to be able to find People with Names that did NOT Contain some text. I started of by adding a new function NotContains but I quickly realized that I would be doubling my functions. The answer was so simple and felt so good. I had already centralized by code that evaluated the function so I just needed to add an optional parameter boolean for tracking if I wanted the standard function or the ‘Not’ version. I added a variable to hold it. I modified the GetList function to use the new variable. Finally I created a new “Not’ function that returns the same FluentComparableList but passes in the boolean as true. Here is the modified FluentComparableList code sample:

 

Public Class FluentComparableList(Of ListType As {IList, New}, ItemType, ParamaterType As IComparable)
    Public InternalList As ListType
    Public InternalFunction As Func(Of ItemType, ParamaterType)
    Public useNot As Boolean


    Sub New(ByRef list As ListType, ByVal _Func As Func(Of ItemType, ParamaterType), Optional ByVal _Not As Boolean = False)
        InternalList = list
        InternalFunction = _Func
        useNot = _Not
    End Sub

    Public Function [Not]() As FluentComparableList(Of ListType, ItemType, ParamaterType)
        Return New FluentComparableList(Of ListType, ItemType, ParamaterType)(InternalList, Function(s) InternalFunction(s), True)
    End Function

    Public Function GetNewList(ByRef _Func As Func(Of ItemType, Boolean))
        GetNewList = New ListType
        For Each item In InternalList
            If useNot Then
                If Not _Func(item) Then GetNewList.Add(item)
            Else
                If _Func(item) Then GetNewList.Add(item)
            End If
        Next
    End Function

    Public Function Greater(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) > 0)
    End Function

    Public Function Lesser(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) < 0)
    End Function
etc..

I do even fewer changes to the FluentStringList. I just pass the boolean on to the base class. I have to shadow the Not class in the base class because I want to return a FluentStringList instead of the FluentStringList that comes out of the base. Now I have the ability to ‘Not’ everything. I can find out how many people don’t have ‘tle’ in their name with:

People.Name.Not.Contains('tle').count

Here are some tests:

Dim target As PersonList

Public Sub MyTestInitialize()
    target = New PersonList
    target.Add(New Person("Bentley", "1/1/1973"))
    target.Add(New Person("Joe", "2/1/1992"))
    target.Add(New Person("Jimmy", "3/1/2005"))
    target.Add(New Person("Karla", "4/1/1984"))
    target.Add(New Person("Cameron", "5/1/1950"))
End Sub


Public Sub FindAll_not_StartsWith()
    Dim Found = target.Name.Not.StartsWith("J")

    Assert.AreEqual(3, Found.Count)
    Assert.AreEqual(5, target.Count, "Has no side-effects")
End Sub


Public Sub BigTest()
    Dim Found = target.Name.Not.EndsWith("y").Name.Not.IndexOf("e").Not.Greater(1)

    Assert.AreEqual(1, Found.Count)
    'Only Karla should match this one
End Sub

I wouldn’t suggest using that many ‘Not’s in production code. It’s amazing how much power we got from so little code. Tell me what you think of this modification in the comments below.

The title of this post might be a little misleading. I am still having Adventures in Creating Fluent Interfaces. I wanted to be able to find People with Names that did NOT Contain some text. I started of by adding a new function NotContains but I quickly realized that I would be doubling my functions. The answer was so simple and felt so good. I had already centralized by code that evaluated the function so I just needed to add an optional parameter boolean for tracking if I wanted the standard function or the ‘Not’ version. I added a variable to hold it. I modified the GetList function to use the new variable. Finally I created a new “Not’ function that returns the same FluentComparableList but passes in the boolean as true. Here is the modified FluentComparableList code sample:

 

Public Class FluentComparableList(Of ListType As {IList, New}, ItemType, ParamaterType As IComparable)
    Public InternalList As ListType
    Public InternalFunction As Func(Of ItemType, ParamaterType)
    Public useNot As Boolean


    Sub New(ByRef list As ListType, ByVal _Func As Func(Of ItemType, ParamaterType), Optional ByVal _Not As Boolean = False)
        InternalList = list
        InternalFunction = _Func
        useNot = _Not
    End Sub

    Public Function [Not]() As FluentComparableList(Of ListType, ItemType, ParamaterType)
        Return New FluentComparableList(Of ListType, ItemType, ParamaterType)(InternalList, Function(s) InternalFunction(s), True)
    End Function

    Public Function GetNewList(ByRef _Func As Func(Of ItemType, Boolean))
        GetNewList = New ListType
        For Each item In InternalList
            If useNot Then
                If Not _Func(item) Then GetNewList.Add(item)
            Else
                If _Func(item) Then GetNewList.Add(item)
            End If
        Next
    End Function

    Public Function Greater(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) > 0)
    End Function

    Public Function Lesser(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) < 0)
    End Function
etc..

I do even fewer changes to the FluentStringList. I just pass the boolean on to the base class. I have to shadow the Not class in the base class because I want to return a FluentStringList instead of the FluentStringList that comes out of the base. Now I have the ability to ‘Not’ everything. I can find out how many people don’t have ‘tle’ in their name with:

People.Name.Not.Contains('tle').count

Here are some tests:

Dim target As PersonList

Public Sub MyTestInitialize()
    target = New PersonList
    target.Add(New Person("Bentley", "1/1/1973"))
    target.Add(New Person("Joe", "2/1/1992"))
    target.Add(New Person("Jimmy", "3/1/2005"))
    target.Add(New Person("Karla", "4/1/1984"))
    target.Add(New Person("Cameron", "5/1/1950"))
End Sub


Public Sub FindAll_not_StartsWith()
    Dim Found = target.Name.Not.StartsWith("J")

    Assert.AreEqual(3, Found.Count)
    Assert.AreEqual(5, target.Count, "Has no side-effects")
End Sub


Public Sub BigTest()
    Dim Found = target.Name.Not.EndsWith("y").Name.Not.IndexOf("e").Not.Greater(1)

    Assert.AreEqual(1, Found.Count)
    'Only Karla should match this one
End Sub

I wouldn’t suggest using that many ‘Not’s in production code. It’s amazing how much power we got from so little code. Tell me what you think of this modification in the comments below.

The title of this post might be a little misleading. I am still having Adventures in Creating Fluent Interfaces. I wanted to be able to find People with Names that did NOT Contain some text. I started of by adding a new function NotContains but I quickly realized that I would be doubling my functions. The answer was so simple and felt so good. I had already centralized by code that evaluated the function so I just needed to add an optional parameter boolean for tracking if I wanted the standard function or the ‘Not’ version. I added a variable to hold it. I modified the GetList function to use the new variable. Finally I created a new “Not’ function that returns the same FluentComparableList but passes in the boolean as true. Here is the modified FluentComparableList code sample:

 

Public Class FluentComparableList(Of ListType As {IList, New}, ItemType, ParamaterType As IComparable)
    Public InternalList As ListType
    Public InternalFunction As Func(Of ItemType, ParamaterType)
    Public useNot As Boolean


    Sub New(ByRef list As ListType, ByVal _Func As Func(Of ItemType, ParamaterType), Optional ByVal _Not As Boolean = False)
        InternalList = list
        InternalFunction = _Func
        useNot = _Not
    End Sub

    Public Function [Not]() As FluentComparableList(Of ListType, ItemType, ParamaterType)
        Return New FluentComparableList(Of ListType, ItemType, ParamaterType)(InternalList, Function(s) InternalFunction(s), True)
    End Function

    Public Function GetNewList(ByRef _Func As Func(Of ItemType, Boolean))
        GetNewList = New ListType
        For Each item In InternalList
            If useNot Then
                If Not _Func(item) Then GetNewList.Add(item)
            Else
                If _Func(item) Then GetNewList.Add(item)
            End If
        Next
    End Function

    Public Function Greater(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) > 0)
    End Function

    Public Function Lesser(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) < 0)
    End Function
etc..

I do even fewer changes to the FluentStringList. I just pass the boolean on to the base class. I have to shadow the Not class in the base class because I want to return a FluentStringList instead of the FluentStringList that comes out of the base. Now I have the ability to ‘Not’ everything. I can find out how many people don’t have ‘tle’ in their name with:

People.Name.Not.Contains('tle').count

Here are some tests:

Dim target As PersonList

Public Sub MyTestInitialize()
    target = New PersonList
    target.Add(New Person("Bentley", "1/1/1973"))
    target.Add(New Person("Joe", "2/1/1992"))
    target.Add(New Person("Jimmy", "3/1/2005"))
    target.Add(New Person("Karla", "4/1/1984"))
    target.Add(New Person("Cameron", "5/1/1950"))
End Sub


Public Sub FindAll_not_StartsWith()
    Dim Found = target.Name.Not.StartsWith("J")

    Assert.AreEqual(3, Found.Count)
    Assert.AreEqual(5, target.Count, "Has no side-effects")
End Sub


Public Sub BigTest()
    Dim Found = target.Name.Not.EndsWith("y").Name.Not.IndexOf("e").Not.Greater(1)

    Assert.AreEqual(1, Found.Count)
    'Only Karla should match this one
End Sub

I wouldn’t suggest using that many ‘Not’s in production code. It’s amazing how much power we got from so little code. Tell me what you think of this modification in the comments below.

The title of this post might be a little misleading. I am still having Adventures in Creating Fluent Interfaces. I wanted to be able to find People with Names that did NOT Contain some text. I started of by adding a new function NotContains but I quickly realized that I would be doubling my functions. The answer was so simple and felt so good. I had already centralized by code that evaluated the function so I just needed to add an optional parameter boolean for tracking if I wanted the standard function or the ‘Not’ version. I added a variable to hold it. I modified the GetList function to use the new variable. Finally I created a new “Not’ function that returns the same FluentComparableList but passes in the boolean as true. Here is the modified FluentComparableList code sample:

 

Public Class FluentComparableList(Of ListType As {IList, New}, ItemType, ParamaterType As IComparable)
    Public InternalList As ListType
    Public InternalFunction As Func(Of ItemType, ParamaterType)
    Public useNot As Boolean


    Sub New(ByRef list As ListType, ByVal _Func As Func(Of ItemType, ParamaterType), Optional ByVal _Not As Boolean = False)
        InternalList = list
        InternalFunction = _Func
        useNot = _Not
    End Sub

    Public Function [Not]() As FluentComparableList(Of ListType, ItemType, ParamaterType)
        Return New FluentComparableList(Of ListType, ItemType, ParamaterType)(InternalList, Function(s) InternalFunction(s), True)
    End Function

    Public Function GetNewList(ByRef _Func As Func(Of ItemType, Boolean))
        GetNewList = New ListType
        For Each item In InternalList
            If useNot Then
                If Not _Func(item) Then GetNewList.Add(item)
            Else
                If _Func(item) Then GetNewList.Add(item)
            End If
        Next
    End Function

    Public Function Greater(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) > 0)
    End Function

    Public Function Lesser(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) < 0)
    End Function
etc..

I do even fewer changes to the FluentStringList. I just pass the boolean on to the base class. I have to shadow the Not class in the base class because I want to return a FluentStringList instead of the FluentStringList that comes out of the base. Now I have the ability to ‘Not’ everything. I can find out how many people don’t have ‘tle’ in their name with:

People.Name.Not.Contains('tle').count

Here are some tests:

Dim target As PersonList

Public Sub MyTestInitialize()
    target = New PersonList
    target.Add(New Person("Bentley", "1/1/1973"))
    target.Add(New Person("Joe", "2/1/1992"))
    target.Add(New Person("Jimmy", "3/1/2005"))
    target.Add(New Person("Karla", "4/1/1984"))
    target.Add(New Person("Cameron", "5/1/1950"))
End Sub


Public Sub FindAll_not_StartsWith()
    Dim Found = target.Name.Not.StartsWith("J")

    Assert.AreEqual(3, Found.Count)
    Assert.AreEqual(5, target.Count, "Has no side-effects")
End Sub


Public Sub BigTest()
    Dim Found = target.Name.Not.EndsWith("y").Name.Not.IndexOf("e").Not.Greater(1)

    Assert.AreEqual(1, Found.Count)
    'Only Karla should match this one
End Sub

I wouldn’t suggest using that many ‘Not’s in production code. It’s amazing how much power we got from so little code. Tell me what you think of this modification in the comments below.

The title of this post might be a little misleading. I am still having Adventures in Creating Fluent Interfaces. I wanted to be able to find People with Names that did NOT Contain some text. I started of by adding a new function NotContains but I quickly realized that I would be doubling my functions. The answer was so simple and felt so good. I had already centralized by code that evaluated the function so I just needed to add an optional parameter boolean for tracking if I wanted the standard function or the ‘Not’ version. I added a variable to hold it. I modified the GetList function to use the new variable. Finally I created a new “Not’ function that returns the same FluentComparableList but passes in the boolean as true. Here is the modified FluentComparableList code sample:

 

Public Class FluentComparableList(Of ListType As {IList, New}, ItemType, ParamaterType As IComparable)
    Public InternalList As ListType
    Public InternalFunction As Func(Of ItemType, ParamaterType)
    Public useNot As Boolean


    Sub New(ByRef list As ListType, ByVal _Func As Func(Of ItemType, ParamaterType), Optional ByVal _Not As Boolean = False)
        InternalList = list
        InternalFunction = _Func
        useNot = _Not
    End Sub

    Public Function [Not]() As FluentComparableList(Of ListType, ItemType, ParamaterType)
        Return New FluentComparableList(Of ListType, ItemType, ParamaterType)(InternalList, Function(s) InternalFunction(s), True)
    End Function

    Public Function GetNewList(ByRef _Func As Func(Of ItemType, Boolean))
        GetNewList = New ListType
        For Each item In InternalList
            If useNot Then
                If Not _Func(item) Then GetNewList.Add(item)
            Else
                If _Func(item) Then GetNewList.Add(item)
            End If
        Next
    End Function

    Public Function Greater(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) > 0)
    End Function

    Public Function Lesser(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) < 0)
    End Function
etc..

I do even fewer changes to the FluentStringList. I just pass the boolean on to the base class. I have to shadow the Not class in the base class because I want to return a FluentStringList instead of the FluentStringList that comes out of the base. Now I have the ability to ‘Not’ everything. I can find out how many people don’t have ‘tle’ in their name with:

People.Name.Not.Contains('tle').count

Here are some tests:

Dim target As PersonList

Public Sub MyTestInitialize()
    target = New PersonList
    target.Add(New Person("Bentley", "1/1/1973"))
    target.Add(New Person("Joe", "2/1/1992"))
    target.Add(New Person("Jimmy", "3/1/2005"))
    target.Add(New Person("Karla", "4/1/1984"))
    target.Add(New Person("Cameron", "5/1/1950"))
End Sub


Public Sub FindAll_not_StartsWith()
    Dim Found = target.Name.Not.StartsWith("J")

    Assert.AreEqual(3, Found.Count)
    Assert.AreEqual(5, target.Count, "Has no side-effects")
End Sub


Public Sub BigTest()
    Dim Found = target.Name.Not.EndsWith("y").Name.Not.IndexOf("e").Not.Greater(1)

    Assert.AreEqual(1, Found.Count)
    'Only Karla should match this one
End Sub

I wouldn’t suggest using that many ‘Not’s in production code. It’s amazing how much power we got from so little code. Tell me what you think of this modification in the comments below.

The title of this post might be a little misleading. I am still having Adventures in Creating Fluent Interfaces. I wanted to be able to find People with Names that did NOT Contain some text. I started of by adding a new function NotContains but I quickly realized that I would be doubling my functions. The answer was so simple and felt so good. I had already centralized by code that evaluated the function so I just needed to add an optional parameter boolean for tracking if I wanted the standard function or the ‘Not’ version. I added a variable to hold it. I modified the GetList function to use the new variable. Finally I created a new “Not’ function that returns the same FluentComparableList but passes in the boolean as true. Here is the modified FluentComparableList code sample:

 

Public Class FluentComparableList(Of ListType As {IList, New}, ItemType, ParamaterType As IComparable)
    Public InternalList As ListType
    Public InternalFunction As Func(Of ItemType, ParamaterType)
    Public useNot As Boolean


    Sub New(ByRef list As ListType, ByVal _Func As Func(Of ItemType, ParamaterType), Optional ByVal _Not As Boolean = False)
        InternalList = list
        InternalFunction = _Func
        useNot = _Not
    End Sub

    Public Function [Not]() As FluentComparableList(Of ListType, ItemType, ParamaterType)
        Return New FluentComparableList(Of ListType, ItemType, ParamaterType)(InternalList, Function(s) InternalFunction(s), True)
    End Function

    Public Function GetNewList(ByRef _Func As Func(Of ItemType, Boolean))
        GetNewList = New ListType
        For Each item In InternalList
            If useNot Then
                If Not _Func(item) Then GetNewList.Add(item)
            Else
                If _Func(item) Then GetNewList.Add(item)
            End If
        Next
    End Function

    Public Function Greater(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) > 0)
    End Function

    Public Function Lesser(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) < 0)
    End Function
etc..

I do even fewer changes to the FluentStringList. I just pass the boolean on to the base class. I have to shadow the Not class in the base class because I want to return a FluentStringList instead of the FluentStringList that comes out of the base. Now I have the ability to ‘Not’ everything. I can find out how many people don’t have ‘tle’ in their name with:

People.Name.Not.Contains('tle').count

Here are some tests:

Dim target As PersonList

Public Sub MyTestInitialize()
    target = New PersonList
    target.Add(New Person("Bentley", "1/1/1973"))
    target.Add(New Person("Joe", "2/1/1992"))
    target.Add(New Person("Jimmy", "3/1/2005"))
    target.Add(New Person("Karla", "4/1/1984"))
    target.Add(New Person("Cameron", "5/1/1950"))
End Sub


Public Sub FindAll_not_StartsWith()
    Dim Found = target.Name.Not.StartsWith("J")

    Assert.AreEqual(3, Found.Count)
    Assert.AreEqual(5, target.Count, "Has no side-effects")
End Sub


Public Sub BigTest()
    Dim Found = target.Name.Not.EndsWith("y").Name.Not.IndexOf("e").Not.Greater(1)

    Assert.AreEqual(1, Found.Count)
    'Only Karla should match this one
End Sub

I wouldn’t suggest using that many ‘Not’s in production code. It’s amazing how much power we got from so little code. Tell me what you think of this modification in the comments below.

The title of this post might be a little misleading. I am still having Adventures in Creating Fluent Interfaces. I wanted to be able to find People with Names that did NOT Contain some text. I started of by adding a new function NotContains but I quickly realized that I would be doubling my functions. The answer was so simple and felt so good. I had already centralized by code that evaluated the function so I just needed to add an optional parameter boolean for tracking if I wanted the standard function or the ‘Not’ version. I added a variable to hold it. I modified the GetList function to use the new variable. Finally I created a new “Not’ function that returns the same FluentComparableList but passes in the boolean as true. Here is the modified FluentComparableList code sample:

 

Public Class FluentComparableList(Of ListType As {IList, New}, ItemType, ParamaterType As IComparable)
    Public InternalList As ListType
    Public InternalFunction As Func(Of ItemType, ParamaterType)
    Public useNot As Boolean


    Sub New(ByRef list As ListType, ByVal _Func As Func(Of ItemType, ParamaterType), Optional ByVal _Not As Boolean = False)
        InternalList = list
        InternalFunction = _Func
        useNot = _Not
    End Sub

    Public Function [Not]() As FluentComparableList(Of ListType, ItemType, ParamaterType)
        Return New FluentComparableList(Of ListType, ItemType, ParamaterType)(InternalList, Function(s) InternalFunction(s), True)
    End Function

    Public Function GetNewList(ByRef _Func As Func(Of ItemType, Boolean))
        GetNewList = New ListType
        For Each item In InternalList
            If useNot Then
                If Not _Func(item) Then GetNewList.Add(item)
            Else
                If _Func(item) Then GetNewList.Add(item)
            End If
        Next
    End Function

    Public Function Greater(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) > 0)
    End Function

    Public Function Lesser(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) < 0)
    End Function
etc..

I do even fewer changes to the FluentStringList. I just pass the boolean on to the base class. I have to shadow the Not class in the base class because I want to return a FluentStringList instead of the FluentStringList that comes out of the base. Now I have the ability to ‘Not’ everything. I can find out how many people don’t have ‘tle’ in their name with:

People.Name.Not.Contains('tle').count

Here are some tests:

Dim target As PersonList

Public Sub MyTestInitialize()
    target = New PersonList
    target.Add(New Person("Bentley", "1/1/1973"))
    target.Add(New Person("Joe", "2/1/1992"))
    target.Add(New Person("Jimmy", "3/1/2005"))
    target.Add(New Person("Karla", "4/1/1984"))
    target.Add(New Person("Cameron", "5/1/1950"))
End Sub


Public Sub FindAll_not_StartsWith()
    Dim Found = target.Name.Not.StartsWith("J")

    Assert.AreEqual(3, Found.Count)
    Assert.AreEqual(5, target.Count, "Has no side-effects")
End Sub


Public Sub BigTest()
    Dim Found = target.Name.Not.EndsWith("y").Name.Not.IndexOf("e").Not.Greater(1)

    Assert.AreEqual(1, Found.Count)
    'Only Karla should match this one
End Sub

I wouldn’t suggest using that many ‘Not’s in production code. It’s amazing how much power we got from so little code. Tell me what you think of this modification in the comments below.

The title of this post might be a little misleading. I am still having Adventures in Creating Fluent Interfaces. I wanted to be able to find People with Names that did NOT Contain some text. I started of by adding a new function NotContains but I quickly realized that I would be doubling my functions. The answer was so simple and felt so good. I had already centralized by code that evaluated the function so I just needed to add an optional parameter boolean for tracking if I wanted the standard function or the ‘Not’ version. I added a variable to hold it. I modified the GetList function to use the new variable. Finally I created a new “Not’ function that returns the same FluentComparableList but passes in the boolean as true. Here is the modified FluentComparableList code sample:

 

Public Class FluentComparableList(Of ListType As {IList, New}, ItemType, ParamaterType As IComparable)
    Public InternalList As ListType
    Public InternalFunction As Func(Of ItemType, ParamaterType)
    Public useNot As Boolean


    Sub New(ByRef list As ListType, ByVal _Func As Func(Of ItemType, ParamaterType), Optional ByVal _Not As Boolean = False)
        InternalList = list
        InternalFunction = _Func
        useNot = _Not
    End Sub

    Public Function [Not]() As FluentComparableList(Of ListType, ItemType, ParamaterType)
        Return New FluentComparableList(Of ListType, ItemType, ParamaterType)(InternalList, Function(s) InternalFunction(s), True)
    End Function

    Public Function GetNewList(ByRef _Func As Func(Of ItemType, Boolean))
        GetNewList = New ListType
        For Each item In InternalList
            If useNot Then
                If Not _Func(item) Then GetNewList.Add(item)
            Else
                If _Func(item) Then GetNewList.Add(item)
            End If
        Next
    End Function

    Public Function Greater(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) > 0)
    End Function

    Public Function Lesser(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) < 0)
    End Function
etc..

I do even fewer changes to the FluentStringList. I just pass the boolean on to the base class. I have to shadow the Not class in the base class because I want to return a FluentStringList instead of the FluentStringList that comes out of the base. Now I have the ability to ‘Not’ everything. I can find out how many people don’t have ‘tle’ in their name with:

People.Name.Not.Contains('tle').count

Here are some tests:

Dim target As PersonList

Public Sub MyTestInitialize()
    target = New PersonList
    target.Add(New Person("Bentley", "1/1/1973"))
    target.Add(New Person("Joe", "2/1/1992"))
    target.Add(New Person("Jimmy", "3/1/2005"))
    target.Add(New Person("Karla", "4/1/1984"))
    target.Add(New Person("Cameron", "5/1/1950"))
End Sub


Public Sub FindAll_not_StartsWith()
    Dim Found = target.Name.Not.StartsWith("J")

    Assert.AreEqual(3, Found.Count)
    Assert.AreEqual(5, target.Count, "Has no side-effects")
End Sub


Public Sub BigTest()
    Dim Found = target.Name.Not.EndsWith("y").Name.Not.IndexOf("e").Not.Greater(1)

    Assert.AreEqual(1, Found.Count)
    'Only Karla should match this one
End Sub

I wouldn’t suggest using that many ‘Not’s in production code. It’s amazing how much power we got from so little code. Tell me what you think of this modification in the comments below.

The title of this post might be a little misleading. I am still having Adventures in Creating Fluent Interfaces. I wanted to be able to find People with Names that did NOT Contain some text. I started of by adding a new function NotContains but I quickly realized that I would be doubling my functions. The answer was so simple and felt so good. I had already centralized by code that evaluated the function so I just needed to add an optional parameter boolean for tracking if I wanted the standard function or the ‘Not’ version. I added a variable to hold it. I modified the GetList function to use the new variable. Finally I created a new “Not’ function that returns the same FluentComparableList but passes in the boolean as true. Here is the modified FluentComparableList code sample:

 

Public Class FluentComparableList(Of ListType As {IList, New}, ItemType, ParamaterType As IComparable)
    Public InternalList As ListType
    Public InternalFunction As Func(Of ItemType, ParamaterType)
    Public useNot As Boolean


    Sub New(ByRef list As ListType, ByVal _Func As Func(Of ItemType, ParamaterType), Optional ByVal _Not As Boolean = False)
        InternalList = list
        InternalFunction = _Func
        useNot = _Not
    End Sub

    Public Function [Not]() As FluentComparableList(Of ListType, ItemType, ParamaterType)
        Return New FluentComparableList(Of ListType, ItemType, ParamaterType)(InternalList, Function(s) InternalFunction(s), True)
    End Function

    Public Function GetNewList(ByRef _Func As Func(Of ItemType, Boolean))
        GetNewList = New ListType
        For Each item In InternalList
            If useNot Then
                If Not _Func(item) Then GetNewList.Add(item)
            Else
                If _Func(item) Then GetNewList.Add(item)
            End If
        Next
    End Function

    Public Function Greater(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) > 0)
    End Function

    Public Function Lesser(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) < 0)
    End Function
etc..

I do even fewer changes to the FluentStringList. I just pass the boolean on to the base class. I have to shadow the Not class in the base class because I want to return a FluentStringList instead of the FluentStringList that comes out of the base. Now I have the ability to ‘Not’ everything. I can find out how many people don’t have ‘tle’ in their name with:

People.Name.Not.Contains('tle').count

Here are some tests:

Dim target As PersonList

Public Sub MyTestInitialize()
    target = New PersonList
    target.Add(New Person("Bentley", "1/1/1973"))
    target.Add(New Person("Joe", "2/1/1992"))
    target.Add(New Person("Jimmy", "3/1/2005"))
    target.Add(New Person("Karla", "4/1/1984"))
    target.Add(New Person("Cameron", "5/1/1950"))
End Sub


Public Sub FindAll_not_StartsWith()
    Dim Found = target.Name.Not.StartsWith("J")

    Assert.AreEqual(3, Found.Count)
    Assert.AreEqual(5, target.Count, "Has no side-effects")
End Sub


Public Sub BigTest()
    Dim Found = target.Name.Not.EndsWith("y").Name.Not.IndexOf("e").Not.Greater(1)

    Assert.AreEqual(1, Found.Count)
    'Only Karla should match this one
End Sub

I wouldn’t suggest using that many ‘Not’s in production code. It’s amazing how much power we got from so little code. Tell me what you think of this modification in the comments below.

The title of this post might be a little misleading. I am still having Adventures in Creating Fluent Interfaces. I wanted to be able to find People with Names that did NOT Contain some text. I started of by adding a new function NotContains but I quickly realized that I would be doubling my functions. The answer was so simple and felt so good. I had already centralized by code that evaluated the function so I just needed to add an optional parameter boolean for tracking if I wanted the standard function or the ‘Not’ version. I added a variable to hold it. I modified the GetList function to use the new variable. Finally I created a new “Not’ function that returns the same FluentComparableList but passes in the boolean as true. Here is the modified FluentComparableList code sample:

 

Public Class FluentComparableList(Of ListType As {IList, New}, ItemType, ParamaterType As IComparable)
    Public InternalList As ListType
    Public InternalFunction As Func(Of ItemType, ParamaterType)
    Public useNot As Boolean


    Sub New(ByRef list As ListType, ByVal _Func As Func(Of ItemType, ParamaterType), Optional ByVal _Not As Boolean = False)
        InternalList = list
        InternalFunction = _Func
        useNot = _Not
    End Sub

    Public Function [Not]() As FluentComparableList(Of ListType, ItemType, ParamaterType)
        Return New FluentComparableList(Of ListType, ItemType, ParamaterType)(InternalList, Function(s) InternalFunction(s), True)
    End Function

    Public Function GetNewList(ByRef _Func As Func(Of ItemType, Boolean))
        GetNewList = New ListType
        For Each item In InternalList
            If useNot Then
                If Not _Func(item) Then GetNewList.Add(item)
            Else
                If _Func(item) Then GetNewList.Add(item)
            End If
        Next
    End Function

    Public Function Greater(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) > 0)
    End Function

    Public Function Lesser(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) < 0)
    End Function
etc..

I do even fewer changes to the FluentStringList. I just pass the boolean on to the base class. I have to shadow the Not class in the base class because I want to return a FluentStringList instead of the FluentStringList that comes out of the base. Now I have the ability to ‘Not’ everything. I can find out how many people don’t have ‘tle’ in their name with:

People.Name.Not.Contains('tle').count

Here are some tests:

Dim target As PersonList

Public Sub MyTestInitialize()
    target = New PersonList
    target.Add(New Person("Bentley", "1/1/1973"))
    target.Add(New Person("Joe", "2/1/1992"))
    target.Add(New Person("Jimmy", "3/1/2005"))
    target.Add(New Person("Karla", "4/1/1984"))
    target.Add(New Person("Cameron", "5/1/1950"))
End Sub


Public Sub FindAll_not_StartsWith()
    Dim Found = target.Name.Not.StartsWith("J")

    Assert.AreEqual(3, Found.Count)
    Assert.AreEqual(5, target.Count, "Has no side-effects")
End Sub


Public Sub BigTest()
    Dim Found = target.Name.Not.EndsWith("y").Name.Not.IndexOf("e").Not.Greater(1)

    Assert.AreEqual(1, Found.Count)
    'Only Karla should match this one
End Sub

I wouldn’t suggest using that many ‘Not’s in production code. It’s amazing how much power we got from so little code. Tell me what you think of this modification in the comments below.

The title of this post might be a little misleading. I am still having Adventures in Creating Fluent Interfaces. I wanted to be able to find People with Names that did NOT Contain some text. I started of by adding a new function NotContains but I quickly realized that I would be doubling my functions. The answer was so simple and felt so good. I had already centralized by code that evaluated the function so I just needed to add an optional parameter boolean for tracking if I wanted the standard function or the ‘Not’ version. I added a variable to hold it. I modified the GetList function to use the new variable. Finally I created a new “Not’ function that returns the same FluentComparableList but passes in the boolean as true. Here is the modified FluentComparableList code sample:

 

Public Class FluentComparableList(Of ListType As {IList, New}, ItemType, ParamaterType As IComparable)
    Public InternalList As ListType
    Public InternalFunction As Func(Of ItemType, ParamaterType)
    Public useNot As Boolean


    Sub New(ByRef list As ListType, ByVal _Func As Func(Of ItemType, ParamaterType), Optional ByVal _Not As Boolean = False)
        InternalList = list
        InternalFunction = _Func
        useNot = _Not
    End Sub

    Public Function [Not]() As FluentComparableList(Of ListType, ItemType, ParamaterType)
        Return New FluentComparableList(Of ListType, ItemType, ParamaterType)(InternalList, Function(s) InternalFunction(s), True)
    End Function

    Public Function GetNewList(ByRef _Func As Func(Of ItemType, Boolean))
        GetNewList = New ListType
        For Each item In InternalList
            If useNot Then
                If Not _Func(item) Then GetNewList.Add(item)
            Else
                If _Func(item) Then GetNewList.Add(item)
            End If
        Next
    End Function

    Public Function Greater(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) > 0)
    End Function

    Public Function Lesser(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) < 0)
    End Function
etc..

I do even fewer changes to the FluentStringList. I just pass the boolean on to the base class. I have to shadow the Not class in the base class because I want to return a FluentStringList instead of the FluentStringList that comes out of the base. Now I have the ability to ‘Not’ everything. I can find out how many people don’t have ‘tle’ in their name with:

People.Name.Not.Contains('tle').count

Here are some tests:

Dim target As PersonList

Public Sub MyTestInitialize()
    target = New PersonList
    target.Add(New Person("Bentley", "1/1/1973"))
    target.Add(New Person("Joe", "2/1/1992"))
    target.Add(New Person("Jimmy", "3/1/2005"))
    target.Add(New Person("Karla", "4/1/1984"))
    target.Add(New Person("Cameron", "5/1/1950"))
End Sub


Public Sub FindAll_not_StartsWith()
    Dim Found = target.Name.Not.StartsWith("J")

    Assert.AreEqual(3, Found.Count)
    Assert.AreEqual(5, target.Count, "Has no side-effects")
End Sub


Public Sub BigTest()
    Dim Found = target.Name.Not.EndsWith("y").Name.Not.IndexOf("e").Not.Greater(1)

    Assert.AreEqual(1, Found.Count)
    'Only Karla should match this one
End Sub

I wouldn’t suggest using that many ‘Not’s in production code. It’s amazing how much power we got from so little code. Tell me what you think of this modification in the comments below.

The title of this post might be a little misleading. I am still having Adventures in Creating Fluent Interfaces. I wanted to be able to find People with Names that did NOT Contain some text. I started of by adding a new function NotContains but I quickly realized that I would be doubling my functions. The answer was so simple and felt so good. I had already centralized by code that evaluated the function so I just needed to add an optional parameter boolean for tracking if I wanted the standard function or the ‘Not’ version. I added a variable to hold it. I modified the GetList function to use the new variable. Finally I created a new “Not’ function that returns the same FluentComparableList but passes in the boolean as true. Here is the modified FluentComparableList code sample:

 

Public Class FluentComparableList(Of ListType As {IList, New}, ItemType, ParamaterType As IComparable)
    Public InternalList As ListType
    Public InternalFunction As Func(Of ItemType, ParamaterType)
    Public useNot As Boolean


    Sub New(ByRef list As ListType, ByVal _Func As Func(Of ItemType, ParamaterType), Optional ByVal _Not As Boolean = False)
        InternalList = list
        InternalFunction = _Func
        useNot = _Not
    End Sub

    Public Function [Not]() As FluentComparableList(Of ListType, ItemType, ParamaterType)
        Return New FluentComparableList(Of ListType, ItemType, ParamaterType)(InternalList, Function(s) InternalFunction(s), True)
    End Function

    Public Function GetNewList(ByRef _Func As Func(Of ItemType, Boolean))
        GetNewList = New ListType
        For Each item In InternalList
            If useNot Then
                If Not _Func(item) Then GetNewList.Add(item)
            Else
                If _Func(item) Then GetNewList.Add(item)
            End If
        Next
    End Function

    Public Function Greater(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) > 0)
    End Function

    Public Function Lesser(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) < 0)
    End Function
etc..

I do even fewer changes to the FluentStringList. I just pass the boolean on to the base class. I have to shadow the Not class in the base class because I want to return a FluentStringList instead of the FluentStringList that comes out of the base. Now I have the ability to ‘Not’ everything. I can find out how many people don’t have ‘tle’ in their name with:

People.Name.Not.Contains('tle').count

Here are some tests:

Dim target As PersonList

Public Sub MyTestInitialize()
    target = New PersonList
    target.Add(New Person("Bentley", "1/1/1973"))
    target.Add(New Person("Joe", "2/1/1992"))
    target.Add(New Person("Jimmy", "3/1/2005"))
    target.Add(New Person("Karla", "4/1/1984"))
    target.Add(New Person("Cameron", "5/1/1950"))
End Sub


Public Sub FindAll_not_StartsWith()
    Dim Found = target.Name.Not.StartsWith("J")

    Assert.AreEqual(3, Found.Count)
    Assert.AreEqual(5, target.Count, "Has no side-effects")
End Sub


Public Sub BigTest()
    Dim Found = target.Name.Not.EndsWith("y").Name.Not.IndexOf("e").Not.Greater(1)

    Assert.AreEqual(1, Found.Count)
    'Only Karla should match this one
End Sub

I wouldn’t suggest using that many ‘Not’s in production code. It’s amazing how much power we got from so little code. Tell me what you think of this modification in the comments below.

The title of this post might be a little misleading. I am still having Adventures in Creating Fluent Interfaces. I wanted to be able to find People with Names that did NOT Contain some text. I started of by adding a new function NotContains but I quickly realized that I would be doubling my functions. The answer was so simple and felt so good. I had already centralized by code that evaluated the function so I just needed to add an optional parameter boolean for tracking if I wanted the standard function or the ‘Not’ version. I added a variable to hold it. I modified the GetList function to use the new variable. Finally I created a new “Not’ function that returns the same FluentComparableList but passes in the boolean as true. Here is the modified FluentComparableList code sample:

 

Public Class FluentComparableList(Of ListType As {IList, New}, ItemType, ParamaterType As IComparable)
    Public InternalList As ListType
    Public InternalFunction As Func(Of ItemType, ParamaterType)
    Public useNot As Boolean


    Sub New(ByRef list As ListType, ByVal _Func As Func(Of ItemType, ParamaterType), Optional ByVal _Not As Boolean = False)
        InternalList = list
        InternalFunction = _Func
        useNot = _Not
    End Sub

    Public Function [Not]() As FluentComparableList(Of ListType, ItemType, ParamaterType)
        Return New FluentComparableList(Of ListType, ItemType, ParamaterType)(InternalList, Function(s) InternalFunction(s), True)
    End Function

    Public Function GetNewList(ByRef _Func As Func(Of ItemType, Boolean))
        GetNewList = New ListType
        For Each item In InternalList
            If useNot Then
                If Not _Func(item) Then GetNewList.Add(item)
            Else
                If _Func(item) Then GetNewList.Add(item)
            End If
        Next
    End Function

    Public Function Greater(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) > 0)
    End Function

    Public Function Lesser(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) < 0)
    End Function
etc..

I do even fewer changes to the FluentStringList. I just pass the boolean on to the base class. I have to shadow the Not class in the base class because I want to return a FluentStringList instead of the FluentStringList that comes out of the base. Now I have the ability to ‘Not’ everything. I can find out how many people don’t have ‘tle’ in their name with:

People.Name.Not.Contains('tle').count

Here are some tests:

Dim target As PersonList

Public Sub MyTestInitialize()
    target = New PersonList
    target.Add(New Person("Bentley", "1/1/1973"))
    target.Add(New Person("Joe", "2/1/1992"))
    target.Add(New Person("Jimmy", "3/1/2005"))
    target.Add(New Person("Karla", "4/1/1984"))
    target.Add(New Person("Cameron", "5/1/1950"))
End Sub


Public Sub FindAll_not_StartsWith()
    Dim Found = target.Name.Not.StartsWith("J")

    Assert.AreEqual(3, Found.Count)
    Assert.AreEqual(5, target.Count, "Has no side-effects")
End Sub


Public Sub BigTest()
    Dim Found = target.Name.Not.EndsWith("y").Name.Not.IndexOf("e").Not.Greater(1)

    Assert.AreEqual(1, Found.Count)
    'Only Karla should match this one
End Sub

I wouldn’t suggest using that many ‘Not’s in production code. It’s amazing how much power we got from so little code. Tell me what you think of this modification in the comments below.

The title of this post might be a little misleading. I am still having Adventures in Creating Fluent Interfaces. I wanted to be able to find People with Names that did NOT Contain some text. I started of by adding a new function NotContains but I quickly realized that I would be doubling my functions. The answer was so simple and felt so good. I had already centralized by code that evaluated the function so I just needed to add an optional parameter boolean for tracking if I wanted the standard function or the ‘Not’ version. I added a variable to hold it. I modified the GetList function to use the new variable. Finally I created a new “Not’ function that returns the same FluentComparableList but passes in the boolean as true. Here is the modified FluentComparableList code sample:

 

Public Class FluentComparableList(Of ListType As {IList, New}, ItemType, ParamaterType As IComparable)
    Public InternalList As ListType
    Public InternalFunction As Func(Of ItemType, ParamaterType)
    Public useNot As Boolean


    Sub New(ByRef list As ListType, ByVal _Func As Func(Of ItemType, ParamaterType), Optional ByVal _Not As Boolean = False)
        InternalList = list
        InternalFunction = _Func
        useNot = _Not
    End Sub

    Public Function [Not]() As FluentComparableList(Of ListType, ItemType, ParamaterType)
        Return New FluentComparableList(Of ListType, ItemType, ParamaterType)(InternalList, Function(s) InternalFunction(s), True)
    End Function

    Public Function GetNewList(ByRef _Func As Func(Of ItemType, Boolean))
        GetNewList = New ListType
        For Each item In InternalList
            If useNot Then
                If Not _Func(item) Then GetNewList.Add(item)
            Else
                If _Func(item) Then GetNewList.Add(item)
            End If
        Next
    End Function

    Public Function Greater(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) > 0)
    End Function

    Public Function Lesser(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) < 0)
    End Function
etc..

I do even fewer changes to the FluentStringList. I just pass the boolean on to the base class. I have to shadow the Not class in the base class because I want to return a FluentStringList instead of the FluentStringList that comes out of the base. Now I have the ability to ‘Not’ everything. I can find out how many people don’t have ‘tle’ in their name with:

People.Name.Not.Contains('tle').count

Here are some tests:

Dim target As PersonList

Public Sub MyTestInitialize()
    target = New PersonList
    target.Add(New Person("Bentley", "1/1/1973"))
    target.Add(New Person("Joe", "2/1/1992"))
    target.Add(New Person("Jimmy", "3/1/2005"))
    target.Add(New Person("Karla", "4/1/1984"))
    target.Add(New Person("Cameron", "5/1/1950"))
End Sub


Public Sub FindAll_not_StartsWith()
    Dim Found = target.Name.Not.StartsWith("J")

    Assert.AreEqual(3, Found.Count)
    Assert.AreEqual(5, target.Count, "Has no side-effects")
End Sub


Public Sub BigTest()
    Dim Found = target.Name.Not.EndsWith("y").Name.Not.IndexOf("e").Not.Greater(1)

    Assert.AreEqual(1, Found.Count)
    'Only Karla should match this one
End Sub

I wouldn’t suggest using that many ‘Not’s in production code. It’s amazing how much power we got from so little code. Tell me what you think of this modification in the comments below.

The title of this post might be a little misleading. I am still having Adventures in Creating Fluent Interfaces. I wanted to be able to find People with Names that did NOT Contain some text. I started of by adding a new function NotContains but I quickly realized that I would be doubling my functions. The answer was so simple and felt so good. I had already centralized by code that evaluated the function so I just needed to add an optional parameter boolean for tracking if I wanted the standard function or the ‘Not’ version. I added a variable to hold it. I modified the GetList function to use the new variable. Finally I created a new “Not’ function that returns the same FluentComparableList but passes in the boolean as true. Here is the modified FluentComparableList code sample:

 

Public Class FluentComparableList(Of ListType As {IList, New}, ItemType, ParamaterType As IComparable)
    Public InternalList As ListType
    Public InternalFunction As Func(Of ItemType, ParamaterType)
    Public useNot As Boolean


    Sub New(ByRef list As ListType, ByVal _Func As Func(Of ItemType, ParamaterType), Optional ByVal _Not As Boolean = False)
        InternalList = list
        InternalFunction = _Func
        useNot = _Not
    End Sub

    Public Function [Not]() As FluentComparableList(Of ListType, ItemType, ParamaterType)
        Return New FluentComparableList(Of ListType, ItemType, ParamaterType)(InternalList, Function(s) InternalFunction(s), True)
    End Function

    Public Function GetNewList(ByRef _Func As Func(Of ItemType, Boolean))
        GetNewList = New ListType
        For Each item In InternalList
            If useNot Then
                If Not _Func(item) Then GetNewList.Add(item)
            Else
                If _Func(item) Then GetNewList.Add(item)
            End If
        Next
    End Function

    Public Function Greater(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) > 0)
    End Function

    Public Function Lesser(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) < 0)
    End Function
etc..

I do even fewer changes to the FluentStringList. I just pass the boolean on to the base class. I have to shadow the Not class in the base class because I want to return a FluentStringList instead of the FluentStringList that comes out of the base. Now I have the ability to ‘Not’ everything. I can find out how many people don’t have ‘tle’ in their name with:

People.Name.Not.Contains('tle').count

Here are some tests:

Dim target As PersonList

Public Sub MyTestInitialize()
    target = New PersonList
    target.Add(New Person("Bentley", "1/1/1973"))
    target.Add(New Person("Joe", "2/1/1992"))
    target.Add(New Person("Jimmy", "3/1/2005"))
    target.Add(New Person("Karla", "4/1/1984"))
    target.Add(New Person("Cameron", "5/1/1950"))
End Sub


Public Sub FindAll_not_StartsWith()
    Dim Found = target.Name.Not.StartsWith("J")

    Assert.AreEqual(3, Found.Count)
    Assert.AreEqual(5, target.Count, "Has no side-effects")
End Sub


Public Sub BigTest()
    Dim Found = target.Name.Not.EndsWith("y").Name.Not.IndexOf("e").Not.Greater(1)

    Assert.AreEqual(1, Found.Count)
    'Only Karla should match this one
End Sub

I wouldn’t suggest using that many ‘Not’s in production code. It’s amazing how much power we got from so little code. Tell me what you think of this modification in the comments below.

The title of this post might be a little misleading. I am still having Adventures in Creating Fluent Interfaces. I wanted to be able to find People with Names that did NOT Contain some text. I started of by adding a new function NotContains but I quickly realized that I would be doubling my functions. The answer was so simple and felt so good. I had already centralized by code that evaluated the function so I just needed to add an optional parameter boolean for tracking if I wanted the standard function or the ‘Not’ version. I added a variable to hold it. I modified the GetList function to use the new variable. Finally I created a new “Not’ function that returns the same FluentComparableList but passes in the boolean as true. Here is the modified FluentComparableList code sample:

 

Public Class FluentComparableList(Of ListType As {IList, New}, ItemType, ParamaterType As IComparable)
    Public InternalList As ListType
    Public InternalFunction As Func(Of ItemType, ParamaterType)
    Public useNot As Boolean


    Sub New(ByRef list As ListType, ByVal _Func As Func(Of ItemType, ParamaterType), Optional ByVal _Not As Boolean = False)
        InternalList = list
        InternalFunction = _Func
        useNot = _Not
    End Sub

    Public Function [Not]() As FluentComparableList(Of ListType, ItemType, ParamaterType)
        Return New FluentComparableList(Of ListType, ItemType, ParamaterType)(InternalList, Function(s) InternalFunction(s), True)
    End Function

    Public Function GetNewList(ByRef _Func As Func(Of ItemType, Boolean))
        GetNewList = New ListType
        For Each item In InternalList
            If useNot Then
                If Not _Func(item) Then GetNewList.Add(item)
            Else
                If _Func(item) Then GetNewList.Add(item)
            End If
        Next
    End Function

    Public Function Greater(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) > 0)
    End Function

    Public Function Lesser(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) < 0)
    End Function
etc..

I do even fewer changes to the FluentStringList. I just pass the boolean on to the base class. I have to shadow the Not class in the base class because I want to return a FluentStringList instead of the FluentStringList that comes out of the base. Now I have the ability to ‘Not’ everything. I can find out how many people don’t have ‘tle’ in their name with:

People.Name.Not.Contains('tle').count

Here are some tests:

Dim target As PersonList

Public Sub MyTestInitialize()
    target = New PersonList
    target.Add(New Person("Bentley", "1/1/1973"))
    target.Add(New Person("Joe", "2/1/1992"))
    target.Add(New Person("Jimmy", "3/1/2005"))
    target.Add(New Person("Karla", "4/1/1984"))
    target.Add(New Person("Cameron", "5/1/1950"))
End Sub


Public Sub FindAll_not_StartsWith()
    Dim Found = target.Name.Not.StartsWith("J")

    Assert.AreEqual(3, Found.Count)
    Assert.AreEqual(5, target.Count, "Has no side-effects")
End Sub


Public Sub BigTest()
    Dim Found = target.Name.Not.EndsWith("y").Name.Not.IndexOf("e").Not.Greater(1)

    Assert.AreEqual(1, Found.Count)
    'Only Karla should match this one
End Sub

I wouldn’t suggest using that many ‘Not’s in production code. It’s amazing how much power we got from so little code. Tell me what you think of this modification in the comments below.

The title of this post might be a little misleading. I am still having Adventures in Creating Fluent Interfaces. I wanted to be able to find People with Names that did NOT Contain some text. I started of by adding a new function NotContains but I quickly realized that I would be doubling my functions. The answer was so simple and felt so good. I had already centralized by code that evaluated the function so I just needed to add an optional parameter boolean for tracking if I wanted the standard function or the ‘Not’ version. I added a variable to hold it. I modified the GetList function to use the new variable. Finally I created a new “Not’ function that returns the same FluentComparableList but passes in the boolean as true. Here is the modified FluentComparableList code sample:

 

Public Class FluentComparableList(Of ListType As {IList, New}, ItemType, ParamaterType As IComparable)
    Public InternalList As ListType
    Public InternalFunction As Func(Of ItemType, ParamaterType)
    Public useNot As Boolean


    Sub New(ByRef list As ListType, ByVal _Func As Func(Of ItemType, ParamaterType), Optional ByVal _Not As Boolean = False)
        InternalList = list
        InternalFunction = _Func
        useNot = _Not
    End Sub

    Public Function [Not]() As FluentComparableList(Of ListType, ItemType, ParamaterType)
        Return New FluentComparableList(Of ListType, ItemType, ParamaterType)(InternalList, Function(s) InternalFunction(s), True)
    End Function

    Public Function GetNewList(ByRef _Func As Func(Of ItemType, Boolean))
        GetNewList = New ListType
        For Each item In InternalList
            If useNot Then
                If Not _Func(item) Then GetNewList.Add(item)
            Else
                If _Func(item) Then GetNewList.Add(item)
            End If
        Next
    End Function

    Public Function Greater(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) > 0)
    End Function

    Public Function Lesser(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) < 0)
    End Function
etc..

I do even fewer changes to the FluentStringList. I just pass the boolean on to the base class. I have to shadow the Not class in the base class because I want to return a FluentStringList instead of the FluentStringList that comes out of the base. Now I have the ability to ‘Not’ everything. I can find out how many people don’t have ‘tle’ in their name with:

People.Name.Not.Contains('tle').count

Here are some tests:

Dim target As PersonList

Public Sub MyTestInitialize()
    target = New PersonList
    target.Add(New Person("Bentley", "1/1/1973"))
    target.Add(New Person("Joe", "2/1/1992"))
    target.Add(New Person("Jimmy", "3/1/2005"))
    target.Add(New Person("Karla", "4/1/1984"))
    target.Add(New Person("Cameron", "5/1/1950"))
End Sub


Public Sub FindAll_not_StartsWith()
    Dim Found = target.Name.Not.StartsWith("J")

    Assert.AreEqual(3, Found.Count)
    Assert.AreEqual(5, target.Count, "Has no side-effects")
End Sub


Public Sub BigTest()
    Dim Found = target.Name.Not.EndsWith("y").Name.Not.IndexOf("e").Not.Greater(1)

    Assert.AreEqual(1, Found.Count)
    'Only Karla should match this one
End Sub

I wouldn’t suggest using that many ‘Not’s in production code. It’s amazing how much power we got from so little code. Tell me what you think of this modification in the comments below.

Fluent iComparable for Everyone

I was working on my Fluent Helper class and I wanted to add a BirthDate field to my example person class. I wanted to be able to filter item if they were Greater or Less than a date. I then realized that I also wanted that for my String class. The String and Date types both support the iComparable interface. Most types do. If I made a generic class using icomparable then I could use that for Date and use it as a base class for Strings. Here is the new class FluentComparableList that can be a base for most other types:

Public Class FluentComparableList(Of ListType As {IList, New}, ItemType, ParamaterType As IComparable)
    Public InternalList As ListType
    Public InternalFunction As Func(Of ItemType, ParamaterType)

    Sub New(ByRef list As ListType, ByVal _Func As Func(Of ItemType, ParamaterType))
        InternalList = list
        InternalFunction = _Func
    End Sub

    Public Function GetNewList(ByRef _Func As Func(Of ItemType, Boolean))
        GetNewList = New ListType
        For Each item In InternalList
             If _Func(item) Then GetNewList.Add(item)
        Next
    End Function

    Public Function Greater(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) > 0)
    End Function

    Public Function Lesser(ByVal i As Integer) As ListType
        Return GetNewList(Function(item) InternalFunction(item).CompareTo(i) < 0)
    End Function
etc...

When I refactored the StringWhere class I renamed it FluentStringList and ended up with:

Public Class FluentStringList(Of ListType As {IList, New}, ItemType)
    Inherits FluentComparableList(Of ListType, ItemType, String)

    Sub New(ByRef list As ListType, ByVal _Func As Func(Of ItemType, String))
        MyBase.New(list, _Func, _Not)
        InternalList = list
        InternalFunction = _Func
    End Sub

    Public Function StartsWith(ByVal value As String) As ListType
        Return GetNewList(Function(item) InternalFunction(item).StartsWith(value))
    End Function

    Public Function EndsWith(ByVal value As String) As ListType
        Return GetNewList(Function(item) InternalFunction(item).EndsWith(value))
    End Function

    Public Function Contains(ByVal value As String) As ListType
        Return GetNewList(Function(item) InternalFunction(item).Contains(value))
    End Function

    Public Function IndexOf(ByVal value As String) As FluentComparableList(Of ListType, ItemType, Integer)
        Return New FluentComparableList(Of ListType, ItemType, Integer)(InternalList, Function(s) InternalFunction(s).IndexOf(value))
    End Function

End Class

You also see a new function on the FluentStringList class called IndexOf. Yes, that is the collection version of the string function IndexOF which tells you the placement of one text string in another. Since it uses the FluentComparableList I can use the integer from the IndexOf and check if it is greater than or less than another integer. For example, Let’s say i want to count all the people with names where the letter ‘e’ was in the name but it was further than the 2nd character from the beginning. It would be as simple as:

People.Name.IndexOf("e").Greater(2).count

Now that was fun! I almost forgot about the BirthDate Field. Here is the Person and the People classes with it implemented:

Public Class Person
    Public Name As String
    Public BirthDate As Date

    Sub New(ByVal _Name As String, ByVal _BirtDate As Date)
        Name = _Name
        BirthDate = _BirtDate
    End Sub

End Class


Public Class PersonList
    Inherits List(Of Person)

    Sub New()
        MyBase.new()
    End Sub

    Sub New(ByVal List As List(Of Person))
        MyBase.New(List)
    End Sub

    Public Function Name() As FluentStringList(Of PersonList, Person)
        Return New FluentStringList(Of PersonList, Person)(Me, Function(s) s.Name)
    End Function

    Public Function BirthDate() As FluentComparableList(Of PersonList, Person, Date)
        Return New FluentComparableList(Of PersonList, Person, Date)(Me, Function(s) s.BirthDate)
    End Function

End Class

Now to see how many people were borne since 1973 I can:

People = New PersonList
People.Add(New Person("Bentley", "1/1/1973"))
People.Add(New Person("Joe", "2/1/1992"))
People.Add(New Person("Jimmy", "3/1/2005"))
People.Add(New Person("Karla", "4/1/1984"))
People.Add(New Person("Cameron", "5/1/1950"))

Debug.Print People.BirthDate.Greater("12/31/1972")
'Prints 4 (only Cameron was borne before 12/31/1972)

I would like to hear what you think in the comments below. Please don’t frustrate, educate!

Adventures in Creating Fluent Interfaces V2

I looked at the code and it looked at the code from my last Adventures in Creating Fluent Interfaces and it looked convoluted and clunky. I also realized that I was creating a copy of most of the objects and more objects with every dot in my syntax. There had to be another way.  I realized that if I could just pass the method I wanted to evaluate (the innerText method in this case) then I could just pass down the original list to the next object in the chain then perform the selection function on it (like the “Contains” function) and if it returned true then I could include that in the next collection. I created lamdas and passed them down in the constructor for the object with the original list and boy does that look better.

To simplify the example I used the canonical Person class that just holds one name. We will add more later.

Public Class Person
    Public Name As String

    Sub New(ByVal _Name As String)
        Name = _Name
    End Sub

End Class

From there we want to get to this code:

People = New PersonList
People.Add(New Person("Bentley"))
People.Add(New Person("Joe"))
People.Add(New Person("Jimmy"))
People.Add(New Person("Karla"))
People.Add(New Person("Cameron"))

Debug.Print People.Name.StartsWith("J").count
'Prints 2 (for Joe and Jimmy)

Debug.Print People.Name.StartsWith("J").Name.EndsWith("y").count
'Prints 1 (for Jimmy)

That looks great! Now how do we get there. First, we want a collection of people.

Public Class PersonList
    Inherits List(Of Person)

    Sub New()
        MyBase.new()
    End Sub

    Sub New(ByVal List As List(Of Person))
        MyBase.New(List)
    End Sub

    Public Function Name() As StringWhere(Of PersonList, Person)
        Return New StringWhere(Of PersonList, Person)(Me, Function(s) s.Name)
    End Function

End Class

So when we call ‘People.Name’ we receive a StringWhere object. That is a generic class that we don’t have to write each time. Here is the beginning of it to give you an idea

Public Class StringWhere(Of ListType As {IList, New}, ItemType)
    Public InternalList As ListType
    Public InternalFunction As Func(Of ItemType, String)

    Sub New(ByRef list As ListType, ByVal _Func As Func(Of ItemType, String))
        InternalList = list
        InternalFunction = _Func
    End Sub

    Public Function GetNewList(ByRef _Func As Func(Of ItemType, Boolean))
        GetNewList = New ListType
        For Each item In InternalList
            If _Func(item) Then GetNewList.Add(item)
        Next
    End Function

    Public Function StartsWith(ByVal value As String) As ListType
        Return GetNewList(Function(item) InternalFunction(item).StartsWith(value))
    End Function

    Public Function Contains(ByVal value As String) As ListType
        Return GetNewList(Function(item) InternalFunction(item).Contains(value))
    End Function
etc...

Now we can iterate over it as many times as we want using StartsWith or EndsWith or Contains and filter what we need. We can add other text fields like LastName or StreetAddress and do the same with them by just also adding it to the collection like we did with the Name field. Now you can easily find the objects you want and look good doing it. Let me know if you have any other ideas or see any disadvantages in this approach or even the whole concept. Please don’t frustrate, educate!

Adventures in Creating Fluent Interfaces

I have been listening to lots of podcasts about programming languages and I find it fascinating. I am trying to be more of a craftsman. As I write code in my job or personal time I ask myself if it is concise and legible. I was working on some software tools to read and manipulate websites programmatically. I found myself writing a lot of code to find a field on the page that matches certain criteria then taking action on the field. I took the opportunity to explore what could be done. I did this before researching a lot so I could discover it myself. Later I compared my work with others.

For example, I had a web page where I needed to click on a specific link. The anchor tag had no ID or Name associated to it so I had to search through all the anchor tags with a specific inner HTML. This looks like:

MyDocument = WebBrowser.Document
MyElements = MyDocument.getElementsByTagName(TagName)
For n = 0 To MyElements.length - 1
    MyElement = MyElements(n)
    If InStr(MyElement.innerHTML, InnerHTML) Then
        ReturnElements.Add(MyElement)
    End If
Next
Dim MyElement As IHTMLElement = ReturnElements(0)
If Not MyElement Is Nothing Then MyElement.click()

That’s not ideal code but you get the point. I wrote this while I was iterating through so I didn’t optimize it. Since i was doing it a lot I made a function that did it all and added it an as extension method to the Web Browser class. It’s use looked like:

webbrowser.ClickByInnerHTMLContainsAndWait("a", "By Channel")

That looked concise but I quickly had other needs and ended up with other extensions like GetElementsIfOuterHTMLContains and GetElementsIfInnerTextContains which resulted in an explosion of methods. It was easy to read but had a complex structure and was difficult to maintain. I decided I wanted a more flexible syntax. Taking a step back I decided to write out what I wanted to say and then I could see if I could bend the language to do it my way. Here is what I wanted:

'In all the text fields on the web page that contain the word 'Bentley' replace it with 'Smart'
WebBrowser.textfields.replace("Bentley", "Smart")
'This will Click the 'Next" link
WebBrowser.links.innertext.contains("Next").first.click
'You can even chain things together
'Click the last link on the web page that begins with 'St' and ends with 'x'
WebBrowser.links.innerText.beginsWith("St").innerTest.EndsWith("x").last.click

That would be great. How could I do that? It could be done with linq.

elements.Where(Function(s) s.innerText.StartsWith("St")).Where(Function(s) s.innerText.EndsWith("x")).Last.click

That works but due to the flexibility of linq you loose some of the brevity.On the other hand, writing a full linq query will allow ‘or’ statements which my syntax would not allow for. Let’s see how we could make it closer to what we want. In effect we want to be have a collection that allows you to filter out items based on the available methods that exist in the item type.

In our example we have a collection of HTML elements. I want to call a method on the collection to filter it down to just links (items with an ’a’ tag which is an anchor). That’s fairly easy to accomplish.

On the collection of links I want to filter based on the innerText value on each of the elements. My syntax indicates that we should be able to calling the innerText method on the collection of links. The decision here is what to return when that is called. My initial plan involved returning a key value pair of strings and the elements. This was returned in a custom type that had methods for all the string methods like StartsWith and Contains. If we called the Contains method it would go through the keys and if the key contained that text it would return that element in the collection. Said another way, it would return all the elements that return true for the selected method. When I was done I would return a list of the original type and I could start again and loop as many times as I wanted. It worked.

'Here is a simple object to contain a paired test string and an element
'This keeps them together
>Public Class TextAndElementPair
    Public Text As String
    Public Element As IHTMLElement
    Sub New(ByVal _text As String, ByVal _element As IHTMLElement)
        Text = _text
        Element = _element
    End Sub
End Class

'Here is the object that is returned from the call to 'InnerText' that allows you to call Contains on all the elements
Public Class ElementsStringFilter
    Dim _elements As List(Of TextAndElementPair)

    Sub New(ByVal Elements As List(Of TextAndElementPair))
        _elements = Elements
    End Sub

    Public Function Contains(ByVal Text As String) As List(Of IHTMLElement)
        Dim Elements As New List(Of IHTMLElement)
        For Each Pair In _elements
            If Pair.Text.Contains(Text) Then Elements.Add(Pair.Element)
        Next
        Return Elements
    End Function
End Class

I looked at the code and it looked convoluted and clunky. I also realized that I was creating a copy of most of the objects and more objects with every dot in my syntax. There had to be another way. In my next post I’ll go over what I did next.