C#

C# 変換演算子(implicitとexplicit)

C#では、C/C++のように型のキャスト(変換)が可能です。
キャストのための演算子としてimplicitとexplicitという変換演算子があります。

英単語としては、下記の意味があります。

implicit 暗黙
explicit 明白な

 

準備

2つの演算子を使った相互変換を行うクラスとして
メートルの2次元データクラス(Meterクラス)と、ミリメーターの2次元データクラス(MilliMeterクラス)を作成して実験をしてみます。

 

Meterクラス

public class Meter
{
    public double X;  // X方向データ(単位:メートル)
    public double Y;  // Y方向データ(単位:メートル)

    public Meter()
    {
        // デフォルトコンストラクタ
    }
    public Meter(double x, double y)
    {
        // 引数付きコンストラクタ
        this.X = x;
        this.Y = y;
    }
}

 

MilliMeterクラス

public class MilliMeter
{
    public double X;  // X方向データ(単位:ミリメートル)
    public double Y;  // Y方向データ(単位:ミリメートル)

    public MilliMeter()
    {
        // デフォルトコンストラクタ
    }

    public MilliMeter(long x, long y)
    {
        // 引数付きコンストラクタ
        this.X = x;
        this.Y = y;
    }
}

 

implicit 変換演算子

implicit 変換演算子は、実装しているクラスを「別の型(クラス)」に変換するための実装を行います。

Meterクラスを使って、implicit 演算子を実装してみます。
implicit 変換演算子には、「MeterクラスをMilliMeterクラスに変換するための処理」を記述します。
ですので、戻り値は’MilliMeter’型、引数は’Meter’型となります。

Meterクラスのコードは下記のようになります。

public class Meter
{
    public double X;  // X方向データ(単位:メートル)
    public double Y;  // Y方向データ(単位:メートル)

    public Meter()
    {
        // デフォルトコンストラクタ
    }
    public Meter(double x, double y)
    {
        // 引数付きコンストラクタ
        this.X = x;
        this.Y = y;
    }

    public static implicit operator MilliMeter(Meter d)
    {
        // MilliMeterクラスへの変換(メートルからミリメートルへの変換)
        return new MilliMeter((long)(d.X * 1000.0), (long)(d.Y * 1000.0));
    }
}

プログラムの実装は下記のようになります。

 

    static void Main(string[] args)
    {
        // メートルからミリメートルに変換します
        Meter data = new Meter(0.1, 0.2);     // Xが10cm、Yが20cm
        MilliMeter data2 = (MilliMeter)data;    // <-- ここでimplicit変換演算子が呼び出されます
        Console.WriteLine(string.Format("X={0}({2}) Y={1}({2})", data2.X, data2.Y, "mm"));
    }

 

このプログラムを実行すると結果は、

X=100(mm) Y=200(mm)

と表示されます。

 

explicit 変換演算子

explicit 変換演算子は、「別の型(クラス)」を実装しているクラスの型に変換するための実装を行います。

MilliMeterクラスを使ってexplicit 演算子を実装してみます。
explicit 変換演算子には、「MilliMeterクラスをMeterクラスに変換するための処理」を記述します。

ですので、戻り値は’Meter’型、引数は’MilliMeter’型となります。

コードは下記のようになります。

public class MilliMeter
{
    public double X;  // X方向データ(単位:ミリメートル)
    public double Y;  // Y方向データ(単位:ミリメートル)

    public MilliMeter()
    {
        // デフォルトコンストラクタ
    }

    public MilliMeter(long x, long y)
    {
        // 引数付きコンストラクタ
        this.X = x;
        this.Y = y;
    }

    public static explicit operator Meter(MilliMeter d)
    {
        // Meterクラスへの変換(ミリメートルからメートルへの変換)
        return new Meter(((double)d.X / 1000.0), ((double)d.Y / 1000.0));
    }
}

プログラムの実装は下記のようになります。

    static void Test2(string[] args)
    {
        // ミリメートルからメートルに変換します
        MilliMeter data = new MilliMeter(100, 200);     // Xが10cm、Yが20cm
        Meter data2 = (Meter)data;    // <-- ここでexplicit変換演算子が呼び出されます
        Console.WriteLine(string.Format("X={0}({2}) Y={1}({2})", data2.X, data2.Y, "m"));
    }

 

このプログラムを実行すると結果は、

X=0.1(m) Y=0.2(m)

と表示されます。

 

ちなみに・・・

今回の例に出てきた片方のクラスに、implicit 変換演算子と explicit 変換演算子の両方を実装するとどうなるか、試してみました。

Meterクラスに実装してみました。

public class Meter
{
    public double X;  // X方向データ(単位:メートル)
    public double Y;  // Y方向データ(単位:メートル)

    public Meter()
    {
        // デフォルトコンストラクタ
    }
    public Meter(double x, double y)
    {
        // 引数付きコンストラクタ
        this.X = x;
        this.Y = y;
    }

    public static implicit operator MilliMeter(Meter d)
    {
        // MilliMeterクラスへの変換(メートルからミリメートルへの変換)
        return new MilliMeter((long)(d.X * 1000.0), (long)(d.Y * 1000.0));
    }

    public static explicit operator Meter(MilliMeter d)
    {
        // Meterクラスへの変換(ミリメートルからメートルへの変換)
        return new Meter(((double)d.X / 1000.0), ((double)d.Y / 1000.0));
    }
}

 

実行するまでもなく、エラーになりました。

エラー CS0457 ‘MilliMeter’ から ‘Meter’ へ変換するときの、あいまいなユーザー定義の変換 ‘MilliMeter.explicit operator Meter(MilliMeter)’ および ‘Meter.explicit operator Meter(MilliMeter)’ です。

 

タイトルとURLをコピーしました