How do you implement a IEqualityComparer<T> in VB.NET?

Anders picture Anders · Apr 8, 2009 · Viewed 7.4k times · Source

I have the following function that loops through a directory and checks for a specified folder and file:

Private Function VerifyPath(ByVal root As String, ByVal folder As String, _ 
                            ByVal file As String) As Boolean

    Dim folders As New List(Of String), files As New List(Of String)
    Dim oDir As New IO.DirectoryInfo(root)

    For Each dir As IO.DirectoryInfo In oDir.GetDirectories
        folders.Add(dir.Name.ToLower)
    Next
    If folders.Contains(folder) Then
        For Each item As IO.FileInfo In oDir.GetFiles
            files.Add(item.Name.ToLower)
        Next
        If files.Contains(file) Then
            Return True
        End If
    End If
    Return False
End Function

The reason I did this method is so I could make sure that the items in each list and the passed file/folder were all lower case, otherwise I would have done something like this:

If oDir.GetDirectories.Contains( _
        New IO.DirectoryInfo(String.Format("{0}\{1}", root, folder))) Then
    If oDir.GetFiles.Contains( _
            New IO.FileInfo(String.Format("{0}\{1}", root, file))) Then
        Return True
    End If
End If
Return False

My colleague mentioned something to me earlier about being able to ignore case by using a comparer. The .Contains extension can have a comparer argument along with the value. I did some searching on google and MSDN, and came up with the following comparer:

Public Class dirCompare
    Implements IEqualityComparer(Of IO.DirectoryInfo)

    Dim theCompare As CaseInsensitiveComparer

    Sub New()
        theCompare = CaseInsensitiveComparer.DefaultInvariant
    End Sub

    Sub New(ByVal culture As CultureInfo)
        theCompare = New CaseInsensitiveComparer(culture)
    End Sub

    Public Function Equals1(ByVal x As System.IO.DirectoryInfo, ByVal y As System.IO.DirectoryInfo) As Boolean Implements System.Collections.Generic.IEqualityComparer(Of System.IO.DirectoryInfo).Equals
        If theCompare.Compare(x.name, y.name) = 0 Then
            Return True
        Else
            Return False
        End If
    End Function

    Public Function GetHashCode1(ByVal obj As System.IO.DirectoryInfo) As Integer Implements System.Collections.Generic.IEqualityComparer(Of System.IO.DirectoryInfo).GetHashCode
        Return obj.ToString.ToLower.GetHashCode
    End Function
End Class

When it gets to the theCompare(x.name, y.name) = 0 line, it errors out and this is the error message:

At least one object must implement IComparable.

Anyone know what this error means and how to go about correcting it?

Answer

Joel Coehoorn picture Joel Coehoorn · Apr 8, 2009

Well you could implement a comparer, but that would be the hard way in this case. You have a couple other options available instead.

The first is that there is already a case-insensitive comparer you can use. There are a couple actually. Look in your intellisense prompts under System.StringComparer.

The second is that strings already have a built-in way to specify a case-insensitive compare:

Dim s As String = "a"
Dim t As String = "A"
If s.Equals(t, StringComparison.InvariantCultureIgnoreCase) Then
   ''//...
End If

And a third is that any searchPattern passed to Directory.GetFiles() or Directory.GetDirectories() is passed directly to the operating system, and Windows is only case-aware for file names, not case-sensitive. So you can pass your folder and file as a search pattern and do your lookup that way.