Structures, Enums, Tuples and Value Semantics

12.1 Structures

Guidelines: keep structures small and immutable (avoid mutable structs: copies cause surprises). Implement IEquatable(Of T) to avoid boxing.

Public Structure Money
    Implements IEquatable(Of Money), IComparable(Of 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
        EnsureSame(a, b)
        Return New Money(a.Amount + b.Amount, a.Currency)
    End Operator
    Public Shared Operator =(a As Money, b As Money) As Boolean
        Return a.Equals(b)
    End Operator
    Public Shared Operator <>(a As Money, b As Money) As Boolean
        Return Not a.Equals(b)
    End Operator
    Public Shared Narrowing Operator CType(m As Money) As Decimal
        Return m.Amount
    End Operator

    Private Shared Sub EnsureSame(a As Money, b As Money)
        If a.Currency <> b.Currency Then Throw New InvalidOperationException("Currency mismatch")
    End Sub

    Public Overloads Function Equals(other As Money) As Boolean Implements IEquatable(Of Money).Equals
        Return Amount = other.Amount AndAlso Currency = other.Currency
    End Function
    Public Overrides Function Equals(obj 
…

12.2 Enums and Flags

<Flags>
Public Enum FileAccessRights As Integer
    None = 0
    Read = 1 << 0
    Write = 1 << 1
    Delete = 1 << 2
    Full = Read Or Write Or Delete
End Enum
Dim rights = FileAccessRights.Read Or FileAccessRights.Write
If rights.HasFlag(FileAccessRights.Write) Then Console.WriteLine("can write")
Dim names = [Enum].GetNames(GetType(FileAccessRights))
Dim parsed = [Enum].Parse(Of FileAccessRights)("Read, Write")

12.3 Tuples and Anonymous Types

VB has no tuple deconstruction. Access the elements by name. Anonymous types can't leave a method in a typed way.

Function Range(values As IEnumerable(Of Integer)) As (Min As Integer, Max As Integer)
    Return (values.Min(), values.Max())
End Function
Dim r = Range({4, 9, 1})
Console.WriteLine($"{r.Min}..{r.Max}")

Dim summary = New With {Key .Region = "West", .Total = 1200D}     ' anonymous type (Key = used in equality)

12.4 Records from C#

VB can consume C# record types (properties, equality, and init setters in object initializers in VB 16.9), but can't declare records or use With expressions. In VB, write immutable classes with ReadOnly properties plus equality members.