Extension Methods and Fluent APIs
Extension methods must live in a Module and carry the <Extension> attribute. They're resolved statically, so instance methods win over extensions. They aren't available on late-bound Object variables.
Imports System.Runtime.CompilerServices
Public Module EnumerableExtensions
<Extension>
Public Function WhereNotNull(Of T As Class)(source As IEnumerable(Of T)) As IEnumerable(Of T)
Return source.Where(Function(x) x IsNot Nothing)
End Function
<Extension>
Public Iterator Function Batch(Of T)(source As IEnumerable(Of T), size As Integer) As IEnumerable(Of List(Of T))
Dim bucket As New List(Of T)(size)
For Each item In source
bucket.Add(item)
If bucket.Count = size Then
Yield bucket
bucket = New List(Of T)(size)
End If
Next
If bucket.Count > 0 Then Yield bucket
End Function
<Extension>
Public Sub ForEachItem(Of T)(source As IEnumerable(Of T), action As Action(Of T))
For Each item In source : action(item) : Next
End Sub
End Module
Public Module StringExtensions
<Extension> Public Function OrDefault(s As String, fallback As String) As String
Return If(String.IsNullOrWhiteSpace(s), fallback, s)
End Function
End Module
' Fluent builder
Public Class EmailBuilder
Private ReadOnly _msg As New EmailMessage()
Public
…