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)’ です。