Fredulom Fredulom - 4 months ago 31
Vb.net Question

VB.NET - how to rectify ".DistinctBy() doesn't return a value on all code paths" warning

Recently I needed way to pull distinct values from a List based upon a particular Object property (in this case, a Timestamp in

DateTime
format) so after some cursory Googling I came across a SO thread where someone provided an extension called 'DistinctBy()' which iterates through a collection and returns items with distinct property values. The code is below;

<Extension()> _
Public Function DistinctBy(Of TSource, TKey)(source As IEnumerable(Of TSource), keySelector As Func(Of TSource, TKey)) As IEnumerable(Of TSource)
Dim seenKeys As New HashSet(Of TKey)()
For Each element As TSource In source
If seenKeys.Add(keySelector(element)) Then
Return CType(element, Global.System.Collections.Generic.IEnumerable(Of TSource))
End If
Next
End Function


The code was originally in C# but I used a code converter to change it into Visual Basic. That said, I'm getting a warning in VS2013 stating that the function doesn't return a value on all codepaths. I'm aware of what the error means and how, in normal circumstances, one would go about fixing them. However, I'm not sure how to proceed considering this is a function which returns an IEnumerable object. I'm not familiar with how IEnumerable functions work and I don't even know whether the function will work at all!

Can anyone provide any clarity on this situation?

Answer

The original code contained state machines with the yield keyword. Meanwhile VB.NET supports it. It's the famous deferred execution of LINQ.

<Extension()> _
Public Iterator Function DistinctBy(Of TSource, TKey)(source As IEnumerable(Of TSource), keySelector As Func(Of TSource, TKey)) As IEnumerable(Of TSource)
    Dim seenKeys As New HashSet(Of TKey)()
    For Each element As TSource In source
        If seenKeys.Add(keySelector(element)) Then
            Yield element
        End If
    Next
End Function

If you had to support a .NET version that doesn't know Yield, you could use this approach which returns all items at once:

<Extension()> _
Public Function DistinctBy(Of TSource, TKey)(source As IEnumerable(Of TSource), keySelector As Func(Of TSource, TKey)) As IEnumerable(Of TSource)
    Dim seenKeys As New HashSet(Of TKey)()
    Dim list = new List(Of TSource)
    For Each element As TSource In source
       If seenKeys.Add(keySelector(element))
            list.Add(element)
       End If
    Next
    return list
End Function
Comments