Comparing IP Addresses in C#

By FoxLearn 1/16/2025 7:30:48 AM   70
Comparing two IP addresses in .NET can be surprisingly tricky.

For those familiar with object-oriented programming, it's easy to assume that using the default equality operator (==) would suffice to compare the contents of two objects.

However, when working with IPAddress objects in C#, this assumption often leads to frustration. The == operator doesn't behave as expected when comparing the contents of two IPAddress objects.

The Pitfall of the == Operator

In C#, when comparing reference type objects, the default behavior of the == operator is to check if both references point to the same instance. This is a common mistake when dealing with IPAddress objects. Using the == operator on two IPAddress objects will only return true if both references point to the same instance, not if the addresses they represent are identical.

For example:

IPAddress addr1 = IPAddress.Parse("192.168.1.100");
IPAddress addr2 = IPAddress.Parse("192.168.1.100");

Console.WriteLine(addr1 == addr2); // False
Console.WriteLine(addr1.Equals(addr2)); // True

Here, the == operator returns false because addr1 and addr2 are two distinct objects in memory, even though they contain the same IP address. On the other hand, Equals() correctly returns true, as it is designed to compare the values contained within the IPAddress objects, not their memory references.

The Correct Way to Compare IP Addresses

The IPAddress class overrides the default Equals method to perform a value comparison rather than a reference comparison. When you use Equals() to compare two IPAddress objects, it checks whether the addresses they represent are identical, not whether they are the same object in memory.

// Override the default Equals method to compare two IPAddress objects
public override bool Equals(object comparand)
{
    // Call the internal Equals method with the comparand object and the flag to compare ScopeId
    return this.Equals(comparand, true);
}

internal bool Equals(object comparand, bool compareScopeId)
{
    // Check if the comparand is of type IPAddress
    if (!(comparand is IPAddress))
    {
        return false; // Return false if the object is not an IPAddress
    }

    // Compare the address families (IPv4 or IPv6) of the two IPAddresses
    if (this.m_Family != ((IPAddress)comparand).m_Family)
    {
        return false; // Return false if the address families don't match
    }

    // If the address family is not IPv6 (i.e., IPv4), compare the internal address representation
    if (this.m_Family != AddressFamily.InterNetworkV6)
    {
        return (((IPAddress)comparand).m_Address == this.m_Address); // Compare the 32-bit internal address for equality
    }

    // If the address family is IPv6, compare the individual segments of the 128-bit address
    for (int i = 0; i < 8; i++)
    {
        // Compare each 16-bit segment of the IPv6 address
        if (((IPAddress)comparand).m_Numbers[i] != this.m_Numbers[i])
        {
            return false; // Return false if any segment does not match
        }
    }

    // Optionally compare the ScopeId field, used to distinguish between different network interfaces
    return ((((IPAddress)comparand).m_ScopeId == this.m_ScopeId) || !compareScopeId);
}

When comparing two IPAddress objects in C#, always use the Equals() method rather than the == operator to ensure you're comparing the actual address values. The == operator only checks for reference equality, which can lead to incorrect results. By using Equals(), you can accurately compare the contents of two IPAddress objects, whether they represent IPv4 or IPv6 addresses.