Skip to content

Instantly share code, notes, and snippets.

@josheinstein
Last active December 27, 2015 08:09
Show Gist options
  • Save josheinstein/7293743 to your computer and use it in GitHub Desktop.
Save josheinstein/7293743 to your computer and use it in GitHub Desktop.
Classes and extension methods that make it easy to work with blocks of IPv4 addresses in .NET.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
namespace Einstein.Net
{
/// <summary>
/// Compares IP addresses to determine numerically which is greater than the other.
/// </summary>
public class IPAddressComparer : Comparer<IPAddress>
{
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="T:IPAddressComparer"/> class.
/// </summary>
public IPAddressComparer( )
{
}
#endregion
#region Properties
private static readonly Lazy<IPAddressComparer> _Default = new Lazy<IPAddressComparer>( );
/// <summary>
/// The default singleton instance of the comparer.
/// </summary>
public static new IPAddressComparer Default
{
get
{
return _Default.Value;
}
}
#endregion
#region Methods
/// <summary>
/// When overridden in a derived class, performs a comparison of two objects of
/// the same type and returns a value indicating whether one object is less than,
/// equal to, or greater than the other.
/// </summary>
/// <param name="x">The first object to compare.</param>
/// <param name="y">The second object to compare.</param>
/// <returns>
/// Value
/// Condition
/// Less than zero
/// <paramref name="x"/> is less than <paramref name="y"/>.
/// Zero
/// <paramref name="x"/> equals <paramref name="y"/>.
/// Greater than zero
/// <paramref name="x"/> is greater than <paramref name="y"/>.
/// </returns>
public override int Compare( IPAddress x, IPAddress y )
{
if ( ReferenceEquals( x, y ) ) {
return 0; // same instance
}
if ( ReferenceEquals( x, null ) ) {
return -1; // nulls are always less than non-null
}
if ( ReferenceEquals( y, null ) ) {
return 1; // non-null is always greater than null
}
if ( x.AddressFamily != y.AddressFamily ) {
throw new ArgumentException( "IP addresses must be of the same address family." );
}
byte[] xBytes = x.GetAddressBytes( );
byte[] yBytes = y.GetAddressBytes( );
if ( xBytes.Length != yBytes.Length ) {
throw new ArgumentException( "IP addresses must be of the same length." );
}
// compare byte by byte
for ( int i = 0 ; i < xBytes.Length ; i++ ) {
if ( xBytes[i] < yBytes[i] ) {
return -1; // x is less
}
else if ( xBytes[i] > yBytes[i] ) {
return 1; // y is less
}
}
return 0; // equal
}
#endregion
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace Einstein.Net
{
/// <summary>
/// Extension methods for IP addresses.
/// </summary>
public static class IPAddressExtensions
{
/// <summary>
/// Determines if the <paramref name="address"/> is between <paramref name="minAddressInclusive"/> and
/// <paramref name="maxAddressInclusive"/>.
/// </summary>
/// <param name="address">The IP address to check.</param>
/// <param name="minAddressInclusive">The minimum (inclusive) address of the range.</param>
/// <param name="maxAddressInclusive">The maximum (inclusive) address of the range.</param>
/// <returns>True if <paramref name="address"/> is between <paramref name="minAddressInclusive"/> and
/// <paramref name="maxAddressInclusive"/>, otherwise false.</returns>
public static bool Between( this IPAddress address, IPAddress minAddressInclusive, IPAddress maxAddressInclusive )
{
Args.ThrowIfNull( address, "value" );
Args.ThrowIfNull( minAddressInclusive, "minAddressInclusive" );
Args.ThrowIfNull( maxAddressInclusive, "maxAddressInclusive" );
var comparer = IPAddressComparer.Default;
int o1 = comparer.Compare( address, minAddressInclusive );
int o2 = comparer.Compare( address, maxAddressInclusive );
return ( o1 >= 0 && o2 <= 0 ) || ( o1 <= 0 && o2 >= 0 );
}
/// <summary>
/// Increments the specified <paramref name="address"/> by one.
/// </summary>
/// <remarks>
/// This method does not check for overflows so incrementing 255.255.255.255 will
/// result in the value 0.0.0.0.
/// </remarks>
/// <returns>The next IP address.</returns>
public static IPAddress Increment( this IPAddress address )
{
Args.ThrowIfNull( address, "address" );
byte[] addressBytes = address.GetAddressBytes( );
// this is going to be slower than an ordinary primitive
// increment operation on a 32 bit integer but the problem
// is that the ip address layout is different than the
// integer layout. for readability and to avoid allocating
// additional space, we'll loop backwards across the
// address to increment it.
for ( int i = addressBytes.Length - 1 ; i >= 0 ; i-- ) {
if ( ++addressBytes[i] != 0 ) {
break;
}
}
return new IPAddress( addressBytes );
}
/// <summary>
/// Applies a <paramref name="subnetMask"/> to an <paramref name="address"/> in order to
/// obtain the broadcast address for the subnet.
/// </summary>
/// <param name="address">The address whose broadcast address to determine.</param>
/// <param name="subnetMask">An IP address that represents the subnet mask.</param>
/// <returns>The broadcast address of the subnet.</returns>
public static IPAddress GetBroadcastAddress( this IPAddress address, IPAddress subnetMask )
{
byte[] ipAdressBytes = address.GetAddressBytes( );
byte[] subnetMaskBytes = subnetMask.GetAddressBytes( );
if ( ipAdressBytes.Length != subnetMaskBytes.Length ) {
throw new ArgumentException( "Lengths of IP address and subnet mask do not match." );
}
byte[] broadcastAddress = new byte[ipAdressBytes.Length];
for ( int i = 0 ; i < broadcastAddress.Length ; i++ ) {
broadcastAddress[i] = (byte)( ipAdressBytes[i] | ( subnetMaskBytes[i] ^ 255 ) );
}
return new IPAddress( broadcastAddress );
}
/// <summary>
/// Applies a <paramref name="subnetMask"/> to an <paramref name="address"/> in order to
/// obtain the first address that falls within the subnet.
/// </summary>
/// <param name="address">The address whose network address to determine.</param>
/// <param name="subnetMask">An IP address that represents the subnet mask.</param>
/// <returns>The first IP address to fall within the subnet.</returns>
public static IPAddress GetNetworkAddress( this IPAddress address, IPAddress subnetMask )
{
byte[] ipAdressBytes = address.GetAddressBytes( );
byte[] subnetMaskBytes = subnetMask.GetAddressBytes( );
if ( ipAdressBytes.Length != subnetMaskBytes.Length ) {
throw new ArgumentException( "Lengths of IP address and subnet mask do not match." );
}
byte[] broadcastAddress = new byte[ipAdressBytes.Length];
for ( int i = 0 ; i < broadcastAddress.Length ; i++ ) {
broadcastAddress[i] = (byte)( ipAdressBytes[i] & ( subnetMaskBytes[i] ) );
}
return new IPAddress( broadcastAddress );
}
/// <summary>
/// Determines if two IP addresses are within the same subnet.
/// </summary>
/// <param name="address2">The an IP address to check.</param>
/// <param name="address">An IP address to check.</param>
/// <param name="subnetMask">The subnet mask of the network.</param>
/// <returns>True if both IPs are in the same subnet, otherwise false.</returns>
public static bool IsInSameSubnet( this IPAddress address2, IPAddress address, IPAddress subnetMask )
{
IPAddress network1 = address.GetNetworkAddress( subnetMask );
IPAddress network2 = address2.GetNetworkAddress( subnetMask );
return network1.Equals( network2 );
}
/// <summary>
/// Returns an IP address formatted as a string in the specified manner.
/// </summary>
/// <param name="ip">The IP address to format.</param>
/// <param name="format">
/// The format specifier, which can be G (general, the default format), P (padded zeroes), or
/// N (numeric, as an unsigned decimal number). P and N are only supported for IPv4.</param>
/// <param name="formatProvider">The format provider or null to use the default provider.</param>
/// <returns>A <see cref="T:String" /> that represents the address in the given format.</returns>
public static string ToString( this IPAddress ip, string format, IFormatProvider formatProvider = null )
{
Args.ThrowIfNull( ip, "ip" );
if ( String.IsNullOrWhiteSpace( format ) ) { format = "g"; }
format = format.ToLowerInvariant( );
// general
if ( format == "g" ) {
return String.Format( formatProvider, "{0}", ip );
}
if ( ip.AddressFamily == AddressFamily.InterNetwork ) {
byte[] bytes = ip.GetAddressBytes( );
// Padded: 001.001.001.001
if ( format == "p" ) {
return String.Format( formatProvider, "{0:000}.{1:000}.{2:000}.{3:000}", bytes[0], bytes[1], bytes[2], bytes[3] );
}
// Numeric: 325344367
if ( format == "n" ) {
return String.Format( formatProvider, "{0:0}",
(uint)bytes[0] << 24 |
(uint)bytes[1] << 16 |
(uint)bytes[2] << 8 |
(uint)bytes[3] );
}
}
throw new ArgumentOutOfRangeException("format", format, "Invalid format string." );
}
}
}
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Serialization;
using System.Text;
using System.Text.RegularExpressions;
namespace Einstein.Net
{
/// <summary>
/// A block of IP addresses which can be expressed in CIDR notation.
/// </summary>
[Serializable]
public sealed class IPv4Block : IFormattable
{
#region Fields
/// <summary>
/// A default instance of IPv4Block that represents an empty range.
/// </summary>
public static readonly IPv4Block Empty = new IPv4Block( );
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="IPv4Block"/> class.
/// </summary>
public IPv4Block( )
{
Address = IPAddress.Any;
Broadcast = IPAddress.Broadcast;
Prefix = 0;
}
/// <summary>
/// Initializes a new instance of the <see cref="T:IPv4Block"/> class.
/// </summary>
/// <param name="address">The IPv4 address.</param>
/// <param name="prefix">The number of significant bits in the routing prefix.</param>
public IPv4Block( string address, int prefix )
{
Args.ThrowIfNullOrEmpty( address, "address" );
Args.ThrowIfOutOfRange( prefix, "prefix", 0, 32 );
IPAddress ip;
if ( !IPAddress.TryParse( address, out ip ) ) {
throw new ArgumentException( "The specified address could not be parsed.", "address" );
}
CheckAddressFamily( ip, "address" );
var mask = ConvertSubnetBitsToMask( prefix );
Prefix = prefix;
Address = IPAddressExtensions.GetNetworkAddress( ip, mask );
Broadcast = IPAddressExtensions.GetBroadcastAddress( ip, mask );
}
/// <summary>
/// Initializes a new instance of the <see cref="IPv4Block"/> struct.
/// </summary>
/// <param name="address">The IPv4 address.</param>
/// <param name="prefix">The number of significant bits in the routing prefix.</param>
public IPv4Block( IPAddress address, int prefix )
{
Args.ThrowIfNull( address, "address" );
Args.ThrowIfOutOfRange( prefix, "prefix", 0, 32 );
CheckAddressFamily( address, "address" );
var mask = ConvertSubnetBitsToMask( prefix );
Prefix = prefix;
Address = IPAddressExtensions.GetNetworkAddress( address, mask );
Broadcast = IPAddressExtensions.GetBroadcastAddress( address, mask );
}
/// <summary>
/// Initializes a new instance of the <see cref="IPv4Block"/> class.
/// </summary>
/// <param name="address">The IPv4 address.</param>
/// <param name="subnetMask">The subnet mask.</param>
public IPv4Block( IPAddress address, IPAddress subnetMask )
{
Args.ThrowIfNull( address, "address" );
Args.ThrowIfNull( subnetMask, "subnetMask" );
CheckAddressFamily( address, "address" );
CheckAddressFamily( subnetMask, "subnetMask" );
Prefix = ConvertSubnetMaskToBits( subnetMask );
Address = IPAddressExtensions.GetNetworkAddress( address, subnetMask );
Broadcast = IPAddressExtensions.GetBroadcastAddress( address, subnetMask );
}
#endregion
#region Properties
/// <summary>
/// Gets the starting address of the subnet range.
/// </summary>
public IPAddress Address
{
get;
private set;
}
/// <summary>
/// Gets the broadcast address of the subnet range.
/// </summary>
public IPAddress Broadcast
{
get;
private set;
}
/// <summary>
/// Gets the number of hosts supported by this <see cref="T:IPv4Block"/>.
/// </summary>
public long Hosts
{
get
{
return Convert.ToInt64( Math.Pow( 2, ( 32 - Prefix ) ) );
}
}
/// <summary>
/// The number of significant bits in the routing mask, for example
/// in the block of 256 addresses that make up 192.168.1.0/24, the
/// 24 is the prefix.
/// </summary>
public int Prefix
{
get;
private set;
}
/// <summary>
/// Gets the subnet portion of the block as an IP address such as 255.255.255.240.
/// </summary>
public IPAddress SubnetMask
{
get
{
return ConvertSubnetBitsToMask( Prefix );
}
}
#endregion
#region Methods
/// <summary>
/// Throws an <see cref="T:ArgumentException"/> if the specified address is not a IPv4 address.
/// </summary>
/// <param name="address">The address to check.</param>
/// <param name="parameterName">The name of the parameter to include in any exceptions that are thrown.</param>
private static void CheckAddressFamily( IPAddress address, string parameterName )
{
if ( address == null ) {
throw new ArgumentNullException( parameterName );
}
if ( address.AddressFamily != AddressFamily.InterNetwork ) {
throw new ArgumentException( "subnetMask must be an IPv4 address.", parameterName );
}
}
/// <summary>
/// Determines whether the block contains the specified IP address or not.
/// </summary>
/// <param name="address">The address to check.</param>
/// <returns>True if the block contains the address, otherwise false.</returns>
public bool Contains( IPAddress address )
{
// is ip greater than or equal to our network address
// AND less than or equal to the broadcast address
if ( address.Between( Address, Broadcast ) ) {
return true;
}
return false;
}
/// <summary>
/// Determines whether the block contains another block.
/// </summary>
/// <param name="block">The block to check.</param>
/// <returns>True if the block contains the other block, otherwise false.</returns>
public bool Contains( IPv4Block block )
{
// is other network address greater than or equal to our network address
// AND less than or equal to the broadcast address
if ( block.Address.Between( Address, Broadcast ) ) {
// AND ALSO,
// the other broadcast address greater than or equal to our network address
// AND less than or equal to the broadcast address
if ( block.Broadcast.Between( Address, Broadcast ) ) {
return true;
}
}
return false;
}
/// <summary>
/// Converts the specified subnet mask (such as 255.255.255.240) into a number of subnet bits (such as /28).
/// </summary>
/// <param name="subnetMask">The subnet mask to convert.</param>
/// <returns>The number of subnet bits in the mask.</returns>
public static int ConvertSubnetMaskToBits( IPAddress subnetMask )
{
Args.ThrowIfNull( subnetMask, "subnetMask" );
if ( subnetMask.AddressFamily != AddressFamily.InterNetwork ) {
throw new ArgumentException( "subnetMask must be an IPv4 address.", "subnetMask" );
}
byte[] bytes = subnetMask.GetAddressBytes( );
Array.Reverse( bytes );
long address = BitConverter.ToUInt32( bytes, 0 );
long hosts = 0xFFFFFFFF - address + 1;
return Convert.ToInt32( 32 - Math.Log( hosts, 2 ) );
}
/// <summary>
/// Converts the specified subnet bits (such as /28) into a subnet mask (such as 255.255.255.240).
/// </summary>
/// <param name="bits">The number of leading bits in the subnet mask. Must be between 0 and 32 inclusive.</param>
/// <returns>A subnet mask such as 255.255.255.240.</returns>
public static IPAddress ConvertSubnetBitsToMask( int bits )
{
Args.ThrowIfOutOfRange( bits, "bits", 0, 32 );
if ( bits == 0 ) {
return new IPAddress( 0 );
}
long mask = 0xFFFFFFFF << ( 32 - bits );
mask = IPAddress.HostToNetworkOrder( mask );
mask = ( mask >> 32 ) & 0xFFFFFFFF;
return new IPAddress( mask );
}
/// <summary>
/// Indicates whether this instance and a specified object are equal.
/// </summary>
/// <param name="obj">Another object to compare to.</param>
/// <returns>
/// true if <paramref name="obj"/> and this instance are the same type and represent the same value; otherwise, false.
/// </returns>
public override bool Equals( object obj )
{
// Null shortcut
if ( ReferenceEquals( obj, null ) ) {
return false;
}
// Self shortcut
if ( ReferenceEquals( obj, this ) ) {
return true;
}
// Type shortcut
if ( obj.GetType( ) != GetType( ) ) {
return false;
}
var other = (IPv4Block)obj;
return Address.Equals( other.Address ) && Prefix.Equals( other.Prefix );
}
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <returns>
/// A 32-bit signed integer that is the hash code for this instance.
/// </returns>
public override int GetHashCode( )
{
var x = new {
Address,
Prefix
};
return x.GetHashCode( );
}
/// <summary>
/// Gets an array of <see cref="T:IPAddress"/> that are within the range of this block.
/// </summary>
/// <returns>The IP addresses in the block.</returns>
public IEnumerable<IPAddress> GetAddressesInRange( )
{
byte[] address = Address.GetAddressBytes( );
byte[] subnet = SubnetMask.GetAddressBytes( );
byte[] start = new byte[address.Length];
for ( int i = 0 ; i < address.Length ; i++ ) {
start[i] = (byte)( address[i] & subnet[i] );
}
int startAddress = BitConverter.ToInt32( start, 0 );
startAddress = IPAddress.NetworkToHostOrder( startAddress );
long hostCount = Hosts;
for ( int i = 0 ; i < hostCount ; i++ ) {
int nextAddress = startAddress + i;
nextAddress = IPAddress.HostToNetworkOrder( nextAddress );
yield return new IPAddress( BitConverter.GetBytes( nextAddress ) );
}
}
/// <summary>
/// Increments this IPv4Block by its block size, such that 192.168.1.0/24 increments
/// to 192.168.2.0/24.
/// </summary>
/// <remarks>
/// If the increment results in an overflow, then an <see cref="T:OverflowException"/>
/// will be thrown. For example, attepting to increment 255.255.255.0/24 will result
/// in an overflow.
/// </remarks>
/// <returns>The next valid IP block with the same block size.</returns>
/// <exception cref="T:OverflowException">The increment resulted in an overflow.</exception>
public IPv4Block Increment( )
{
// Go from the broadcast address to the next ip
var nextAddress = IPAddressExtensions.Increment( Broadcast );
var nextBlock = new IPv4Block( nextAddress, Prefix );
// Make sure the new address is greater than the previous or
// else throw an overflow exception.
if ( IPAddressComparer.Default.Compare( Address, nextBlock.Address ) >= 0 ) {
throw new OverflowException( );
}
return nextBlock;
}
/// <summary>
/// Determines whether this block overlaps another block.
/// </summary>
/// <param name="block">The block to check.</param>
/// <returns>True if the block overlaps the other block, otherwise false.</returns>
public bool Overlaps( IPv4Block block )
{
if ( block.Address.Between( Address, Broadcast ) ) {
return true;
}
if ( block.Broadcast.Between( Address, Broadcast ) ) {
return true;
}
if ( Address.Between( block.Address, block.Broadcast ) ) {
return true;
}
if ( Broadcast.Between( block.Address, block.Broadcast ) ) {
return true;
}
return false;
}
/// <summary>
/// Parses the specified <paramref name="input"/> string into a <see cref="T:IPv4Block"/>.
/// </summary>
/// <remarks>
/// This method can only parse strings in the format of 192.168.1.0/24 or 192.168.1.0/255.255.255.0.
/// It cannot parse a range of addresses as is produced by passing the R format specifier to the
/// ToString method.
/// </remarks>
/// <param name="input">The input string.</param>
/// <returns>A parsed IPv4Block class.</returns>
public static IPv4Block Parse( string input )
{
IPv4Block output;
if ( IPv4Block.TryParse( input, out output ) ) {
return output;
}
else {
throw new FormatException( "The input string was not in the correct format." );
}
}
/// <summary>
/// Attempts to parse the specified <paramref name="input"/> string into an <see cref="T:IPv4Block"/>
/// and returns true if the parse succeeds, otherwise false.
/// </summary>
/// <remarks>
/// This method can only parse strings in the format of 192.168.1.0/24 or 192.168.1.0/255.255.255.0.
/// It cannot parse a range of addresses as is produced by passing the R format specifier to the
/// ToString method.
/// </remarks>
/// <param name="input">The input string.</param>
/// <param name="output">A parsed IPv4Block class.</param>
/// <returns>True if the parse succeeded, otherwise false.</returns>
public static bool TryParse( string input, out IPv4Block output )
{
if ( !String.IsNullOrEmpty( input ) ) {
int n = input.IndexOf( '/' );
if ( n > 0 ) {
string address = input.Substring( 0, n ).Trim( );
string subnet = input.Substring( n + 1 ).Trim( );
IPAddress ip;
if ( IPAddress.TryParse( address, out ip ) ) {
// try to parse as ip/bits
int s;
if ( Int32.TryParse( subnet, out s ) ) {
try {
output = new IPv4Block( ip, s );
return true;
}
catch {
}
}
// try to parse as ip/mask
IPAddress subnetMask;
if ( IPAddress.TryParse( subnet, out subnetMask ) ) {
try {
output = new IPv4Block( ip, subnetMask );
return true;
}
catch {
}
}
}
}
}
output = null;
return false;
}
/// <summary>
/// Returns the fully qualified type name of this instance.
/// </summary>
/// <returns>
/// A <see cref="T:System.String"/> containing a fully qualified type name.
/// </returns>
public override string ToString( )
{
return String.Format( CultureInfo.InvariantCulture, "{0}/{1}", Address, Prefix );
}
#endregion
#region IFormattable Members
/// <summary>
/// Returns a <see cref="T:String" /> that represents this instance.
/// </summary>
/// <param name="format">The format.</param>
/// <returns>
/// A <see cref="T:String" /> that represents this instance.
/// </returns>
public string ToString( string format )
{
return ToString( format, null );
}
/// <summary>
/// Returns a <see cref="T:String" /> that represents the current IPv4Block in a specified
/// format.
/// </summary>
/// <param name="format">
/// The format specifier, which can be C (CIDR, the default format), CC (CIDR with padded zeroes),
/// S (address with subnet mask), SS (padded address with padded subnet), R (range of IP addresses),
/// or RR (a range of addresses that are padded with zeroes as necessary.)
/// </param>
/// <param name="formatProvider">The format provider or null to use the default provider.</param>
/// <returns>A <see cref="T:String" /> that represents this instance.</returns>
public string ToString( string format, IFormatProvider formatProvider )
{
if ( String.IsNullOrWhiteSpace( format ) ) { format = "c"; }
format = format.ToLowerInvariant( );
// CIDR: 192.168.1.0/24
if ( format == "c" ) {
return Address.ToString( ) + "/" + Prefix.ToString( "0" );
}
// CIDR: 192.168.001.000/08
if ( format == "cc" ) {
return IPAddressExtensions.ToString( Address, "p", formatProvider ) + "/" + Prefix.ToString( "00" );
}
// Subnet Mask: 192.168.0.0/255.255.255.0
if ( format == "s" ) {
return Address.ToString( ) + "/" + SubnetMask.ToString( );
}
// Subnet Mask: 192.168.001.000/255.255.255.000
if ( format == "ss" ) {
return IPAddressExtensions.ToString( Address, "p", formatProvider ) + "/" + IPAddressExtensions.ToString( SubnetMask, "p", formatProvider );
}
// Range: 192.168.1.0-192.168.1.255
if ( format == "r" ) {
return Address.ToString( ) + "-" + Broadcast.ToString( );
}
// Range: 192.168.001.000-192.168.001.255
if ( format == "rr" ) {
return IPAddressExtensions.ToString( Address, "p", formatProvider ) + "-" + IPAddressExtensions.ToString( Broadcast, "p", formatProvider );
}
throw new ArgumentOutOfRangeException( "format", format, "Invalid format string." );
}
#endregion
#region Operators
/// <summary>
/// Implements the operator ==.
/// </summary>
/// <param name="lhs">The LHS.</param>
/// <param name="rhs">The RHS.</param>
/// <returns>The result of the operator.</returns>
public static bool operator ==( IPv4Block lhs, IPv4Block rhs )
{
// Self shortcut
if ( ReferenceEquals( lhs, rhs ) ) {
return true;
}
// Null shortcut
if ( ReferenceEquals( lhs, null ) ) {
return false;
}
// Null shortcut
if ( ReferenceEquals( rhs, null ) ) {
return false;
}
return lhs.Equals( rhs );
}
/// <summary>
/// Implements the operator !=.
/// </summary>
/// <param name="lhs">The LHS.</param>
/// <param name="rhs">The RHS.</param>
/// <returns>The result of the operator.</returns>
public static bool operator !=( IPv4Block lhs, IPv4Block rhs )
{
return !( lhs == rhs );
}
#endregion
#region Conversions
/// <summary>
/// Performs an explicit conversion from <see cref="T:String"/> to <see cref="T:IPv4Block"/>.
/// </summary>
/// <param name="str">The string.</param>
/// <returns>The result of the conversion.</returns>
public static explicit operator IPv4Block( string str )
{
return IPv4Block.Parse( str );
}
/// <summary>
/// Performs an explicit conversion from <see cref="T:IPv4Block"/> to <see cref="T:String"/>.
/// </summary>
/// <param name="ip">The ip block.</param>
/// <returns>The result of the conversion.</returns>
public static explicit operator string( IPv4Block ip )
{
return ip.ToString( );
}
#endregion
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment