Iterators, Extension Methods, and Operator Overloading
Prerequisites: LINQ
Iterators with Yield
An Iterator Function produces a sequence one item at a time with
Yield. Items are computed only as they're requested:
Module Program
Iterator Function Fibonacci() As IEnumerable(Of Long)
Dim a = 0L, b = 1L
Do
Yield a
Dim nextValue = a + b
a = b
b = nextValue
Loop
End Function
Iterator Function Countdown(from As Integer) As IEnumerable(Of Integer)
For i = from To 1 Step -1
Console.WriteLine($" (producing {i})")
Yield i
Next
End Function
Sub Main()
Console.WriteLine(String.Join(" ", Fibonacci().Take(10)))
Console.WriteLine(Fibonacci().First(Function(n) n > 1000))
For Each n In Countdown(2)
Console.WriteLine(n)
Next
End Sub
End Module
0 1 1 2 3 5 8 13 21 34
1597
(producing 2)
2
(producing 1)
1
Fibonacci loops forever, but Take(10) only asks for ten values. The
"producing" lines show the lazy, step-by-step evaluation.
Extension methods
An extension method adds a method to an existing type — even one you
didn't write, like String. It lives in a module and is marked
<Extension>:
Imports System.Runtime.CompilerServices
Module StringExtensions
<Extension>
Public Function Shout(text As String) As String
Return text.ToUpper() & "!"
End Function
<Extension>
Public Function WordCount(text As String) As Integer
Return text.Split({" "c}, StringSplitOptions.RemoveEmptyEntries).Length
End Function
End Module
Module Program
Sub Main()
Console.WriteLine("hello".Shout())
Console.WriteLine("the quick brown fox".WordCount())
End Sub
End Module
HELLO!
4
The first parameter is the value the method is called on. LINQ's
Where, Select, and Sum are extension methods on
IEnumerable(Of T).
Operator overloading
Public Structure Money
Public ReadOnly Property Amount As Decimal
Public ReadOnly Property Currency As String
Public Sub New(amount As Decimal, currency As String)
Me.Amount = amount
Me.Currency = currency
End Sub
Public Shared Operator +(a As Money, b As Money) As Money
If a.Currency <> b.Currency Then Throw New InvalidOperationException("Currency mismatch.")
Return New Money(a.Amount + b.Amount, a.Currency)
End Operator
Public Shared Operator *(a As Money, factor As Decimal) As Money
Return New Money(a.Amount * factor, a.Currency)
End Operator
Public Shared Operator =(a As Money, b As Money) As Boolean
Return a.Amount = b.Amount AndAlso a.Currency = b.Currency
End Operator
Public Shared Operator <>(a As Money, b As Money) As Boolean
Return Not (a = b)
End Operator
Public Overrides Function ToString() As String
Return $"{Amount:F2} {Currency}"
End Function
End Structure
Module Program
Sub Main()
Dim price As New Money(19.99D, "USD")
Dim total = price * 3 + New Money(5D, "USD")
Console.WriteLine(total)
Console.WriteLine(total = New Money(64.97D, "USD"))
End Sub
End Module
64.97 USD
True
Operators are Shared Operator members. Some must come in pairs: =
with <>, < with >. When you overload =, also override Equals
and GetHashCode, so that collections and LINQ agree with your
operator — the VB compiler doesn't remind you.