LoginSignup
40
40

More than 5 years have passed since last update.

[.NET] クラスや構造体を作る時におすすめのインターフェース(数値型編)

Last updated at Posted at 2016-02-19

こんにちはー!ニアです。
今回は.NETでクラスや構造体を作る時に、継承して実装すると便利なインターフェースを紹介していきます。

ここでは、数値型の構造体を例として取り上げます。

1. 数値系の構造体の場合

例えば、System.Int32System.Doubleなどの構造体は、以下の5つのインターフェースを実装しています。

  • IComparable
  • IFormattable
  • IConvertible
  • IComparable<T>
  • IEquatable<T>
System.Int32
[SerializableAttribute]
[ComVisibleAttribute(true)]
public struct Int32 : IComparable, IFormattable, IConvertible, 
    IComparable<int>, IEquatable<int>
System.Double
[SerializableAttribute]
[ComVisibleAttribute(true)]
public struct Double : IComparable, IFormattable, IConvertible, 
    IComparable<double>, IEquatable<double>

ここからは、その5つのインターフェースの概要と、それらを実装することでできることを紹介していきます。

1.1. IComparableインターフェース、IComparable<T>インターフェース

概要

IComparableインターフェースは、2つのインスタンスの大小を比較した結果を返すCompareToメソッドを持ちます。

IComparable
[ComVisibleAttribute(true)]
public interface IComparable {
    int CompareTo( object obj );
}

IComparable<T>インターフェースは、IComparableインターフェースのジェネリクス版です。

IComparable(T)
[ComVisibleAttribute(true)]
public interface IComparable<in T> {
    int CompareTo( T other );
}

これらのインターフェースを継承して実装することでできること

なお、IComparable.CompareToとIComparable<T>.CompareToの両方を継承した場合、IComparable<T>.CompareToを優先して呼び出されます。

1.2. IFormattableインターフェース

概要

IFormattableインターフェースは、書式を指定してインスタンスの値を文字列に変換するToString(String, IFormatProvider)メソッドを持ちます。

IFormattable
[ComVisibleAttribute(true)]
public interface IFormattable {
    string ToString( string format, IFormatProvider provider );
}

このインターフェースを継承して実装することでできること

1.3. IConvertibleインターフェース

概要

IConvertibleインターフェースは、インスタンスの値をプリミティブ型1及びDateTime構造体に変換するメソッドを持ちます。

IConvertible
[ComVisibleAttribute(true)]
public interface IConvertible {
    TypeCode GetTypeCode();
    bool ToBoolean( IFormatProvider provider );
    byte ToByte( IFormatProvider provider );
    char ToChar( IFormatProvider provider );
    DateTime ToDateTime( IFormatProvider provider );
    decimal ToDecimal( IFormatProvider provider );
    double ToDouble( IFormatProvider provider );
    short ToInt16( IFormatProvider provider );
    int ToInt32( IFormatProvider provider );
    long ToInt64( IFormatProvider provider );
    sbyte ToSByte( IFormatProvider provider );
    float ToSingle( IFormatProvider provider );
    string ToString( IFormatProvider provider );
    object ToType( Type conversionType, IFormatProvider provider );
    ushort ToUInt16( IFormatProvider provider );
    uint ToUInt32( IFormatProvider provider );
    ulong ToUInt64( IFormatProvider provider );
}

実装するメソッドが17個とちょっと多めですね(汗)。

このインターフェースを継承して実装することでできること

  • Convertクラスを利用してプリミティブ型及びDateTime型に変換する

1.4. IEquatable<T>インターフェース

概要

IEquatable<T>インターフェースは、2つのインスタンスの値が等しいかどうかを判別するEqualsメソッドを持ちます。

IEquatable(T)
[ComVisibleAttribute(true)]
public interface IEquatable<in T> {
    bool Equals( T other );
}

このインターフェースを継承して実装することでできること

  • リストにおける指定した要素の存在の確認したり、インデックスの位置を求めたりする(List<T>.Contains / List<T>.IndexOf)などの処理
  • HashSet<T>やDictionary<T>のキーの比較2

2. インターフェースの実装例

ここでは固定小数点演算を扱う構造体における、インターフェースの実装例を載せます。

固定小数点演算を扱う構造体における、インターフェースの実装例
using System;
using System.Text.RegularExpressions;

public struct Q10 : IComparable, IFormattable, IConvertible, 
    IComparable<Q10>, IEquatable<Q10> {

    // 固定小数点演算の内部の値
    public short Value { get; private set; }

    // IComparableの実装
    int IComparable.CompareTo( object obj ) {
        // objがnull or Q10以外の時
        if( obj == null || !( obj is Q10 ) ){
            return 1;
        }
        // 内部の値同士で比較します。
        return Value.CompareTo( ( ( Q10 )obj ).Value );
    }

    // IComparable<Q10>の実装
    int IComparable<Q10>.CompareTo( Q10 other ) {
        // 内部の値同士で比較します。
        return Value.CompareTo( other.Value );
    }

    // IEquatable<Q10>の実装
    bool IEquatable<Q10>.Equals( Q10 other ) {
        // 内部の値同士で比較します。
        return Value.Equals( other.Value );
    }

    // IConvertibleの実装(一部のみ抜粋)
    double IConvertible.ToDouble( IFormatProvider provider ) {
        // 内部の値 / 1024.0 ⇒ 等価な倍精度浮動小数点数に変換します。
        return Value / 1024.0;
    }

    int IConvertible.ToInt32( IFormatProvider provider ) {
        // 内部の値 / 1024 ⇒ 等価な符号付き32ビット整数に変換します。
        return Value >> 10;
    }

    static Regex regf = new Regex( @"F\d*?|f\d*?" );
    static Regex regd = new Regex( @"ID\d*?|id\d*?" );

    // IFormattableの実装
    string IFormattable.ToString( string format, IFormatProvider provider ) {
        if( format == null ) {
            return ( Value / 1024.0 ).ToString();
        }
        // 書式が「F[数字]」の時は、等価な倍精度浮動小数点数を書式指定して文字列に変換します。
        else if( regf.IsMatch( format ) ) {
            return ( Value / 1024.0 ).ToString( format );
        }
        // 書式が「ID[数字]」の時は、内部の値を書式指定して文字列に変換します。
        else if( regd.IsMatch( format ) ) {
            return Value.ToString( format );
        }

        throw new FormatException();
    }

}

インターフェースを上手に利用して、作成するクラスや構造体をより便利にしてみてはいかがでしょう。
それでは、See you next!


  1. プリミティブ型 : Boolean、Byte、SByte、Char、Int16、Int32、Int64、UInt16、UInt32、UInt64、Single、Double、Decimal、String 

  2. まずGetHashCodeメソッドの戻り値を比較し、値が等しい時にIEquatable<T>.Equalsメソッドが呼び出されます。 

40
40
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
40
40