2010-10-20T03:24:57の更新内容

programming/netfx2/overview/typeconversion/index.wiki.txt

current previous
1,2316 1,357
~
${smdncms:title,型変換 (Parse, Convert, IConvertible)}
${smdncms:title,型変換演算子を用いたユーザー定義の型変換}
+
${smdncms:keywords,型変換,拡大変換,縮小変換,Widening,Narrowing,implicit,explicit,CType,キャスト,Convert,IConvertible,ToString,Parse,TryParse}
 
${smdncms:meta,toc-amazonlivelink-keyword,books-jp,.net framework}
${smdncms:meta,toc-amazonlivelink-keyword,books-jp,.net framework}
-
ユーザー定義の型変換とは、自分で定義したクラスや構造体同士のキャストにおける動作を定義することです。 例えば、int型からdouble型、またその反対のキャストは既に定義されていますが、自分で定義した構造体StructAとStructB同士のキャストは定義されていません。 ユーザー定義の型変換とは、このような状況に於いて型変換の動作を定義することなのです。
-
#googleadunit
 

        

        
~
ここでは.NET Frameworkにおける基本型の型変換と、ユーザ定義の型変換、および.NET Frameworkで用意されている型変換のためのクラス・インターフェイスについて解説します。
*ユーザー定義の型変換
~

          
ユーザー定義の型変換の例として、int型の値を持ち、ToString()でその値を十六進数で表示する構造体Hexadecimalを用いて、実際に型変換の定義をしてみます。
+
-関連するページ
+
--[[programming/netfx2/string_formatting]]
+
--Visual Basic
+
---[[programming/vb8/diff_from_7x/02_ctype_operator_overload]]
+
---[[programming/vb.net/basics/04_conversion]]
+

          
+
*基本型の型変換
+
**暗黙的・明示的な型変換
+
もっとも基本的な型変換に、代入時の暗黙の型変換があります。 変換に際してデータの欠損や桁落ち、オーバーフローが発生しない拡大変換(widening conversion)が行われる場合に、暗黙の型変換が行われます。
+

          
+
#tabpage(C#)
 
#code(cs){{
#code(cs){{
 
using System;
using System;
 

        

        
~
class Sample
namespace TypeConversion
 
{
{
+
  static void Main()
+
  {
+
    int i;
+
    double d;
+

          
+
    i = 42;
+
    d = i; // intからdoubleへの暗黙の型変換が行われる
+

          
+
    Console.WriteLine(i);
+
    Console.WriteLine(d);
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim i As Integer
+
    Dim d As Double
+

          
+
    i = 42
+
    d = i // IntegerからDoubleへの暗黙の型変換が行われる
+

          
+
    Console.WriteLine(i)
+
    Console.WriteLine(d)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
 

        

        
~
#prompt{{
    public struct Hexadecimal
~
42
    {
+
42
+
}}
 

        

        
~
逆に、変換するとデータの欠損や桁落ち、オーバーフローが発生し得る縮小変換(narrowing conversion)を行う場合、暗黙の型変換は出来ません。 この場合、キャストや型変換関数を使って明示的な型変換を行う必要があります。
        public int DecimalValue;
 

        

        
~
#tabpage(C#)
        // コンストラクタ
~
#code(cs){{
        public Hexadecimal( int val )
~
using System;
        {
-
            DecimalValue = val;
-
        }
-

          
-
        // Object.ToString() をオーバーライド
-
        public override string ToString()
-
        {
-
            return DecimalValue.ToString("X");
-
        }
-

          
-
        // Hexadecimal から int への型変換 (明示的)
-
        public static explicit operator int( Hexadecimal hex ) 
-
        {
-
            return hex.DecimalValue;
-
        }
-

          
-
        // int から Hexadecimal への型変換 (明示的)
-
        public static explicit operator Hexadecimal( int dec ) 
-
        {
-
            return new Hexadecimal( dec );
-
        }
 

        

        
~
class Sample
    }
+
{
+
  static void Main()
+
  {
+
    double d;
+
    int i;
+

          
+
    d = 3.14;
+
    i = (int)d; // doubleからintへのキャスト
+

          
+
    Console.WriteLine(d);
+
    Console.WriteLine(i);
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim d As Double
+
    Dim i As Integer
+

          
+
    d = 3.14
+
    i = CInt(d) ' DoubleからIntegerへの型変換
+

          
+
    Console.WriteLine(d)
+
    Console.WriteLine(i)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
 

        

        
+
#prompt{{
+
3.14
+
3
+
}}
 

        

        
~
明示的な型変換によりオーバーフローが発生した場合、&msdn(netfx,type,System.OverflowException){OverflowException};がスローされます。 どのような場合に拡大変換または縮小変換となるかは、以下のドキュメントでまとめられています。
    class Class1
-
    {
-
        [STAThread]
-
        static void Main(string[] args)
-
        {
 

        

        
~
-C#
            Hexadecimal hex;
~
--&msdn(netfx,id,y5b434w4){暗黙的な数値変換の一覧表 (C# リファレンス)};
            int dec;
+
--&msdn(netfx,id,yht2cx7b){明示的な数値変換の一覧表 (C# リファレンス)};
+
-VB
+
--&msdn(netfx,id,k1e94s7e){拡大変換と縮小変換};
+
--&msdn(netfx,id,kca3w8x6){暗黙の型変換と明示的な型変換};
+

          
+
**文字列への/からの変換
+
***文字列への変換 (ToString)
+
基本型から文字列への変換にはToStringメソッドを使うことが出来ます。 単純な文字列化の他、書式を指定した変換も出来ます。
 

        

        
~
#tabpage(C#)
            hex = (Hexadecimal)256;
~
#code(cs){{
            dec = (int)hex;
+
using System;
 

        

        
~
class Sample
            Console.WriteLine( hex );
~
{
            Console.WriteLine( hex.DecimalValue );
~
  static void Main()
            Console.WriteLine( dec );
+
  {
+
    int i = 42;
+
    double d = 3.141592;
+

          
+
    string s1 = i.ToString();
+
    string s2 = i.ToString("D8");
+
    string s3 = d.ToString();
+
    string s4 = d.ToString("F4");
+

          
+
    Console.WriteLine(s1);
+
    Console.WriteLine(s2);
+
    Console.WriteLine(s3);
+
    Console.WriteLine(s4);
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim i As Integer = 42
+
    Dim d As Double = 3.141592
+

          
+
    Dim s1 As String = i.ToString()
+
    Dim s2 As String = i.ToString("D8")
+
    Dim s3 As String = d.ToString()
+
    Dim s4 As String = d.ToString("F4")
+

          
+
    Console.WriteLine(s1)
+
    Console.WriteLine(s2)
+
    Console.WriteLine(s3)
+
    Console.WriteLine(s4)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
 

        

        
~
#prompt{{
        }
~
42
    }
+
00000042
+
3.141592
+
3.1416
+
}}
+

          
+
書式には、桁数や指数形式・16進形式などを指定することが出来ます。 変換時の書式については、[[programming/netfx2/string_formatting]]で詳しく解説しています。
+

          
+
***文字列からの変換 (Parse, TryParse)
+
文字列から基本型への変換には&msdn(netfx,method,System.Int32.Parse){Int32.Parse};、&msdn(netfx,method,System.Double.Parse){Double.Parse};などのParseメソッドを使うことが出来ます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    int i1 = int.Parse("42");
+
    int i2 = int.Parse("000042");
+
    double d1 = double.Parse("3.14");
+
    double d2 = double.Parse("1.23E+3");
+

          
+
    Console.WriteLine(i1);
+
    Console.WriteLine(i2);
+
    Console.WriteLine(d1);
+
    Console.WriteLine(d2);
+
  }
 
}
}
 
}}
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim i1 As Integer = Integer.Parse("42")
+
    Dim i2 As Integer = Integer.Parse("000042")
+
    Dim d1 As Double = Double.Parse("3.14")
+
    Dim d2 As Double = Double.Parse("1.23E+3")
+

          
+
    Console.WriteLine(i1)
+
    Console.WriteLine(i2)
+
    Console.WriteLine(d1)
+
    Console.WriteLine(d2)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
 

        

        
~
#prompt{{
#prompt(実行結果){{
~
42
100
~
42
256
~
3.14
256
~
1230
Press any key to continue
 
}}
}}
 

        

        
~
このメソッドでは、変換できない形式の場合は&msdn(netfx,type,System.FormatException){FormatException};、変換した値が型の最大値・最小値を超える場合は&msdn(netfx,type,System.OverflowException){OverflowException};がスローされます。
ひとまず構造体の動作は置いておいて、Main()メソッドでの流れを見ていくことにします。 最初に、44・45行目でHexadecimal・int 型の変数を一つずつ用意しています。 変数の名前であるhexは十六進数(Hexadecimal)、decは十進数(Decimal)という意味合いでつけました。 47行目において、int型定数である256をHexadecimal型にキャストしてhexに代入します。 続いて48行目で、たったいま256をHexadecimal型にキャストして代入したhexを、さらにint型に戻してdecに代入しています。
 

        

        
~
変換時に例外をスローさせたくない場合は、&msdn(netfx,method,System.Int32.TryParse){Int32.TryParse};、&msdn(netfx,method,System.Double.TryParse){Double.TryParse};などのTryParseメソッドを使うことが出来ます。 このメソッドは、変換できた場合はtrue、変換できなかった場合はfalseを返し、変換した値は2番目の引数(out/ByRef)に代入されます。
これらの値を表示しているのが50〜52行目です。 hex.DecimalValueはhexが実際に保持するint型の値です。 hexを WriteLine()メソッドによって表示する場合、ToString()によってその変数の持つ値は文字列に変換されてから表示されます。  Hexadecimal.ToString()ではObject.ToString()をオーバーライドし、 Hexadecimal.DecimalValueを十六進数で表記した文字列に変換した値を返します。
 

        

        
~
#tabpage(C#)
ここで、実際の動作について見てみることにします。 まず、47行目でint型の定数をHexadecimal型にキャストしましたが、このとき実際には30〜32行目にあるようなintからHexadecimalへのキャストを行うためのコードが呼び出されます。 これらのコードは型変換演算子といいます。 この演算子ではint型を引数にとり、Hexadecimal型を戻り値として返します。 intからHexadecimal へキャストする場合の動作を定義しているのでこのような構成になっています。 この演算子ではキャスト前のint値を元に新たなHexadecimal値を作成して返してやることによってHexadecimalへのキャストを実現しています。
+
#code(cs){{
+
using System;
 

        

        
~
class Sample
逆に、Hexadecimalからintへキャストしている48行目では、24〜27行目の演算子が呼び出され、ここで定義されている動作に従ってキャストが行われます。 つまり、元のHexadecimal値からDecimalValueの値を返すことによってint型へのキャストとしています。
+
{
+
  static void Main()
+
  {
+
    int i;
+

          
+
    if (int.TryParse("42", out i))
+
      Console.WriteLine(i);
+
    else
+
      Console.WriteLine("変換できない値");
+

          
+
    if (int.TryParse("abc", out i))
+
      Console.WriteLine(i);
+
    else
+
      Console.WriteLine("変換できない値");
+

          
+
    if (int.TryParse("01234567890123456789", out i))
+
      Console.WriteLine(i);
+
    else
+
      Console.WriteLine("変換できない値");
+

          
+
    double d;
+

          
+
    if (double.TryParse("3.14", out d))
+
      Console.WriteLine(d);
+
    else
+
      Console.WriteLine("変換できない値");
+

          
+
    if (double.TryParse("1.2345E+6789", out d))
+
      Console.WriteLine(d);
+
    else
+
      Console.WriteLine("変換できない値");
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim i As Integer
+

          
+
    If Integer.TryParse("42", i) Then
+
      Console.WriteLine(i)
+
    Else
+
      Console.WriteLine("変換できない値")
+
    End If
+

          
+
    If Integer.TryParse("abc", i) Then
+
      Console.WriteLine(i)
+
    Else
+
      Console.WriteLine("変換できない値")
+
    End If
+

          
+
    If Integer.TryParse("01234567890123456789", i) Then
+
      Console.WriteLine(i)
+
    Else
+
      Console.WriteLine("変換できない値")
+
    End If
+

          
+
    Dim d As Double
+

          
+
    If Double.TryParse("3.14", d) Then
+
      Console.WriteLine(d)
+
    Else
+
      Console.WriteLine("変換できない値")
+
    End If
+

          
+
    If Double.TryParse("1.2345E+6789", d) Then
+
      Console.WriteLine(d)
+
    Else
+
      Console.WriteLine("変換できない値")
+
    End If
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
42
+
変換できない値
+
変換できない値
+
3.14
+
変換できない値
+
}}
 

        

        
~
***基数を指定した変換 (Convert.ToXXX)
さらに、演算子の定義を見てみると、public staticになっています。 これは演算子はクラス・構造体のインスタンスに関わらず静的に存在するもので、なおかつpublicでなければならないからです。 explicitキーワードについてはこの次で解説します。
+
16進数、8進数などの文字列から整数型に変換するには、&msdn(netfx,method,System.Convert){Convertクラス};の以下のメソッドを使うことが出来ます。 また、基数を指定して整数型の値を文字列に変換することもできます。 いずれのメソッドも、二つめの引数に変換する文字列(または数値)の基数を指定します。
 

        

        
~
|*基数を指定した変換を行うことが出来るメソッド
*明示的なキャストと暗黙的なキャスト
~
|~メソッド|~動作|h
続いてexplicitキーワードについてですが、これはキャストが明示的に行われることを示しています。 つまり、「値 = (型)値」という形式のキャストをしなければならないことを定めていますが、これをimplicitに変えると暗黙的なキャストを行うことが許されるようになります。 そのように変えたものが次の例です。
+
|>|~文字列から整数型への変換|
+
|&msdn(netfx,id,c7xhf79k){ToByte(String, Int32)};|文字列からByteへの変換|
+
|&msdn(netfx,id,4wxkt09k){ToInt16(String, Int32)};|文字列からInt16への変換|
+
|&msdn(netfx,id,1k20k614){ToInt32(String, Int32)};|文字列からInt32への変換|
+
|&msdn(netfx,id,yk8t68tb){ToInt64(String, Int32)};|文字列からInt64への変換|
+
|&msdn(netfx,id,k5ss9sbw){ToSByte(String, Int32)};|文字列からSByteへの変換|
+
|&msdn(netfx,id,8444cfyw){ToUInt16(String, Int32)};|文字列からUInt16への変換|
+
|&msdn(netfx,id,swz6z5ks){ToUInt32(String, Int32)};|文字列からUInt32への変換|
+
|&msdn(netfx,id,3zk09b81){ToUInt64(String, Int32)};|文字列からUInt64への変換|
+
|>|~整数型から文字列への変換|
+
|&msdn(netfx,id,8s62fh68){ToString(Byte, Int32)};|Byteから文字列への変換|
+
|&msdn(netfx,id,b1kwkfdz){ToString(Int16, Int32)};|Int16から文字列への変換|
+
|&msdn(netfx,id,14kwkz77){ToString(Int32, Int32)};|Int32から文字列への変換|
+
|&msdn(netfx,id,6wse73s4){ToString(Int64, Int32)};|Int64から文字列への変換|
 

        

        
~
基数として指定できる値は、2、8、10、16のいずれかで、これ以外の基数を指定するとArgumentExceptionがスローされます。 また、基数に10以外を指定してマイナス記号で始まる文字列を変換しようとした場合もArgumentExceptionとなります。 さらに、16進数を表す"0x"や"&h"などのプレフィックスを含む文字列を変換しようとした場合は、FormatExceptionがスローされます。
#code(cs,ユーザー定義の型変換(暗黙的)){{
+

          
+
以下は、基数を指定して文字列と整数型の値を変換する例です。
+

          
+
#tabpage(C#)
+
#code(cs){{
 
using System;
using System;
 

        

        
~
class Sample
namespace TypeConversion
 
{
{
+
  static void Main()
+
  {
+
    // 数値128を文字列に変換
+
    Console.WriteLine(Convert.ToString(128, 2)); // 2進数に変換
+
    Console.WriteLine(Convert.ToString(128, 8)); // 8進数に変換
+
    Console.WriteLine(Convert.ToString(128, 10)); // 10進数に変換
+
    Console.WriteLine(Convert.ToString(128, 16)); // 16進数に変換
+

          
+
    Console.WriteLine();
+

          
+
    // 文字列"100"を数値に変換
+
    Console.WriteLine(Convert.ToInt32("100", 2)); // 2進数として変換
+
    Console.WriteLine(Convert.ToInt32("100", 8)); // 8進数として変換
+
    Console.WriteLine(Convert.ToInt32("100", 10)); // 10進数として変換
+
    Console.WriteLine(Convert.ToInt32("100", 16)); // 16進数として変換
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' 数値128を文字列に変換
+
    Console.WriteLine(Convert.ToString(128, 2)) ' 2進数に変換
+
    Console.WriteLine(Convert.ToString(128, 8)) ' 8進数に変換
+
    Console.WriteLine(Convert.ToString(128, 10)) ' 10進数に変換
+
    Console.WriteLine(Convert.ToString(128, 16)) ' 16進数に変換
+

          
+
    Console.WriteLine()
+

          
+
    ' 文字列"100"を数値に変換
+
    Console.WriteLine(Convert.ToInt32("100", 2)) ' 2進数として変換
+
    Console.WriteLine(Convert.ToInt32("100", 8)) ' 8進数として変換
+
    Console.WriteLine(Convert.ToInt32("100", 10)) ' 10進数として変換
+
    Console.WriteLine(Convert.ToInt32("100", 16)) ' 16進数として変換
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
 

        

        
~
#prompt{{
    public struct Hexadecimal
~
10000000
    {
+
200
+
128
+
80
 

        

        
~
4
        public int DecimalValue;
+
64
+
100
+
256
+
}}
 

        

        
~
**実数型から整数型への変換 (Round, Ceiling, Floor)
        // コンストラクタ
~
float(Single)、doubleおよびdecimalから整数型へ変換する際に、&msdn(netfx,method,System.Math.Round){Math.Round};、&msdn(netfx,method,System.Math.Ceiling){Math.Ceiling};、&msdn(netfx,method,System.Math.Floor){Math.Floor};といった端数処理のメソッドと組み合わせて変換することが出来ます。 以下のコードを使って、これらのメソッドを使った場合とキャストによる変換を行った場合の端数処理の結果を比較してみます。
        public Hexadecimal( int val )
-
        {
-
            DecimalValue = val;
-
        }
-

          
-
        // Object.ToString() をオーバーライド
-
        public override string ToString()
-
        {
-
            return DecimalValue.ToString("X");
-
        }
-

          
-
        // Hexadecimal から int への型変換 (暗黙的)
-
        public static implicit operator int( Hexadecimal hex ) 
-
        {
-
            return hex.DecimalValue;
-
        }
-

          
-
        // int から Hexadecimal への型変換 (暗黙的)
-
        public static implicit operator Hexadecimal( int dec ) 
-
        {
-
            return new Hexadecimal( dec );
-
        }
 

        

        
~
#code(cs){{
    }
+
using System;
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    Console.WriteLine("{0,6}| {1,12} {2,12} {3,12} {4,12} {5,12} {6,12}| {0,6}",
+
                      "value",
+
                      "cast",
+
                      "Round",
+
                      "ToEven",
+
                      "AwayFromZero",
+
                      "Ceiling",
+
                      "Floor");
 

        

        
+
    Console.WriteLine(new string('-', 14 * 7));
 

        

        
~
    for (double d = 2.75; -2.75 <= d; d -= 0.25)
    class Class1
 
    {
    {
~
      Console.WriteLine("{0,6:F2}| {1,12:F2} {2,12:F2} {3,12:F2} {4,12:F2} {5,12:F2} {6,12:F2}| {0,6:F2}",
        [STAThread]
~
                        d,
        static void Main(string[] args)
~
                        (int)d,
        {
+
                        Math.Round(d),
+
                        Math.Round(d, MidpointRounding.ToEven),
+
                        Math.Round(d, MidpointRounding.AwayFromZero),
+
                        Math.Ceiling(d),
+
                        Math.Floor(d));
+
    }
+
  }
+
}
+
}}
+

          
+
#prompt{{
+
 value|         cast        Round       ToEven AwayFromZero      Ceiling        Floor|  value
+
--------------------------------------------------------------------------------------------------
+
  2.75|         2.00         3.00         3.00         3.00         3.00         2.00|   2.75
+
  2.50|         2.00         2.00         2.00         3.00         3.00         2.00|   2.50
+
  2.25|         2.00         2.00         2.00         2.00         3.00         2.00|   2.25
+
  2.00|         2.00         2.00         2.00         2.00         2.00         2.00|   2.00
+
  1.75|         1.00         2.00         2.00         2.00         2.00         1.00|   1.75
+
  1.50|         1.00         2.00         2.00         2.00         2.00         1.00|   1.50
+
  1.25|         1.00         1.00         1.00         1.00         2.00         1.00|   1.25
+
  1.00|         1.00         1.00         1.00         1.00         1.00         1.00|   1.00
+
  0.75|         0.00         1.00         1.00         1.00         1.00         0.00|   0.75
+
  0.50|         0.00         0.00         0.00         1.00         1.00         0.00|   0.50
+
  0.25|         0.00         0.00         0.00         0.00         1.00         0.00|   0.25
+
  0.00|         0.00         0.00         0.00         0.00         0.00         0.00|   0.00
+
 -0.25|         0.00         0.00         0.00         0.00         0.00        -1.00|  -0.25
+
 -0.50|         0.00         0.00         0.00        -1.00         0.00        -1.00|  -0.50
+
 -0.75|         0.00        -1.00        -1.00        -1.00         0.00        -1.00|  -0.75
+
 -1.00|        -1.00        -1.00        -1.00        -1.00        -1.00        -1.00|  -1.00
+
 -1.25|        -1.00        -1.00        -1.00        -1.00        -1.00        -2.00|  -1.25
+
 -1.50|        -1.00        -2.00        -2.00        -2.00        -1.00        -2.00|  -1.50
+
 -1.75|        -1.00        -2.00        -2.00        -2.00        -1.00        -2.00|  -1.75
+
 -2.00|        -2.00        -2.00        -2.00        -2.00        -2.00        -2.00|  -2.00
+
 -2.25|        -2.00        -2.00        -2.00        -2.00        -2.00        -3.00|  -2.25
+
 -2.50|        -2.00        -2.00        -2.00        -3.00        -2.00        -3.00|  -2.50
+
 -2.75|        -2.00        -3.00        -3.00        -3.00        -2.00        -3.00|  -2.75
+
}}
 

        

        
~
それぞれの動作について整理すると次のようになります。
            Hexadecimal hex;
~
:キャスト|端数は切り捨てられる。 (0への丸め)
            int dec;
+
:Math.Round + MidpointRounding.ToEven&br;Math.Round|端数は偶数方向に丸められる。 (最近接偶数への丸め、銀行家丸め)&br;Math.RoundでMidpointRoundingを指定しなかった場合はMidpointRounding.ToEvenと同じ結果となる。 また、VBでのCIntの結果もこれと同じ。
+
:Math.Round + MidpointRounding.AwayFromZero|端数はゼロから遠い方に丸められる。 (四捨五入)
+
:Math.Ceiling|数値以下の最大の整数(数直線上で正の方向にある次の整数)に丸められる。 (正の無限大への丸め)
+
:Math.Floor|数値以上の最小の整数(数直線上で負の方向にある次の整数)に丸められる。 (負の無限大への丸め)
 

        

        
~
Math.Roundメソッドは、戻り値に含まれる小数部分の桁数を指定できるため、丸めを行う際の桁を指定することが出来ます。 次の例は、桁を指定して四捨五入する例です。
            hex = 256;
-
            dec = hex;
 

        

        
~
#tabpage(C#)
            Console.WriteLine( hex );
~
#code(cs){{
            Console.WriteLine( hex.DecimalValue );
~
using System;
            Console.WriteLine( dec );
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    Console.WriteLine("{0,8}| {1,12} {2,12} {3,12} {4,12}| {0,8}",
+
                      "value",
+
                      "Round(0)",
+
                      "Round(1)",
+
                      "Round(2)",
+
                      "Round(3)");
 

        

        
~
    Console.WriteLine(new string('-', 14 * 5));
        }
+

          
+
    for (double d = 1.5; -1.5 <= d; d -= 0.125)
+
    {
+
      Console.WriteLine("{0,8:F4}| {1,12:F4} {2,12:F4} {3,12:F4} {4,12:F4}| {0,8:F4}",
+
                        d,
+
                        Math.Round(d, 0, MidpointRounding.AwayFromZero),
+
                        Math.Round(d, 1, MidpointRounding.AwayFromZero),
+
                        Math.Round(d, 2, MidpointRounding.AwayFromZero),
+
                        Math.Round(d, 3, MidpointRounding.AwayFromZero));
 
    }
    }
+
  }
 
}
}
 
}}
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Console.WriteLine("{0,8}| {1,12} {2,12} {3,12} {4,12}| {0,8}", _
+
                      "value", _
+
                      "Round(0)", _
+
                      "Round(1)", _
+
                      "Round(2)", _
+
                      "Round(3)")
+

          
+
    Console.WriteLine(New String("-"c, 14 * 5))
+

          
+
    For d As Double = 1.5 To -1.5 Step -0.125
+
      Console.WriteLine("{0,8:F4}| {1,12:F4} {2,12:F4} {3,12:F4} {4,12:F4}| {0,8:F4}", _
+
                        d, _
+
                        Math.Round(d, 0, MidpointRounding.AwayFromZero), _
+
                        Math.Round(d, 1, MidpointRounding.AwayFromZero), _
+
                        Math.Round(d, 2, MidpointRounding.AwayFromZero), _
+
                        Math.Round(d, 3, MidpointRounding.AwayFromZero))
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
 

        

        
~
#prompt{{
#prompt(実行結果){{
~
   value|     Round(0)     Round(1)     Round(2)     Round(3)|    value
256
~
----------------------------------------------------------------------
256
~
  1.5000|       2.0000       1.5000       1.5000       1.5000|   1.5000
256
~
  1.3750|       1.0000       1.4000       1.3800       1.3750|   1.3750
Press any key to continue
+
  1.2500|       1.0000       1.3000       1.2500       1.2500|   1.2500
+
  1.1250|       1.0000       1.1000       1.1300       1.1250|   1.1250
+
  1.0000|       1.0000       1.0000       1.0000       1.0000|   1.0000
+
  0.8750|       1.0000       0.9000       0.8800       0.8750|   0.8750
+
  0.7500|       1.0000       0.8000       0.7500       0.7500|   0.7500
+
  0.6250|       1.0000       0.6000       0.6300       0.6250|   0.6250
+
  0.5000|       0.0000       0.5000       0.5000       0.5000|   0.5000
+
  0.3750|       0.0000       0.4000       0.3800       0.3750|   0.3750
+
  0.2500|       0.0000       0.3000       0.2500       0.2500|   0.2500
+
  0.1250|       0.0000       0.1000       0.1300       0.1250|   0.1250
+
  0.0000|       0.0000       0.0000       0.0000       0.0000|   0.0000
+
 -0.1250|       0.0000      -0.1000      -0.1300      -0.1250|  -0.1250
+
 -0.2500|       0.0000      -0.3000      -0.2500      -0.2500|  -0.2500
+
 -0.3750|       0.0000      -0.4000      -0.3800      -0.3750|  -0.3750
+
 -0.5000|       0.0000      -0.5000      -0.5000      -0.5000|  -0.5000
+
 -0.6250|      -1.0000      -0.6000      -0.6300      -0.6250|  -0.6250
+
 -0.7500|      -1.0000      -0.8000      -0.7500      -0.7500|  -0.7500
+
 -0.8750|      -1.0000      -0.9000      -0.8800      -0.8750|  -0.8750
+
 -1.0000|      -1.0000      -1.0000      -1.0000      -1.0000|  -1.0000
+
 -1.1250|      -1.0000      -1.1000      -1.1300      -1.1250|  -1.1250
+
 -1.2500|      -1.0000      -1.3000      -1.2500      -1.2500|  -1.2500
+
 -1.3750|      -1.0000      -1.4000      -1.3800      -1.3750|  -1.3750
+
 -1.5000|      -2.0000      -1.5000      -1.5000      -1.5000|  -1.5000
+
}}
+

          
+
**バイト配列への/からの変換
+
***基本型とバイト配列への/からの変換
+
&msdn(netfx,method,System.BitConverter.GetBytes){BitConverter.GetBytesメソッド};を用いると、基本型をバイト配列に変換することが出来ます。 逆にBitConverter.ToXXXメソッドを用いると、バイト配列から基本型に変換することが出来ます。 ToXXXメソッドでは、変換するバイト配列と、変換する最初のインデックスを指定する必要があります。 なお、&msdn(netfx,method,System.BitConverter.ToString){BitConverter.ToString};メソッドは、各バイトをハイフンで連結した文字列を返します。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    byte[] bytes = new byte[] {0xff, 0xff, 0x80, 0x00};
+

          
+
    Console.WriteLine(BitConverter.ToString(bytes, 0));
+
    Console.WriteLine("{0}   0x{0:X8}", BitConverter.ToInt32(bytes, 0));
+
    Console.WriteLine("{0}   0x{0:X4}", BitConverter.ToInt16(bytes, 0));
+
    Console.WriteLine("{0}   0x{0:X4}", BitConverter.ToInt16(bytes, 2));
+
    Console.WriteLine(BitConverter.ToSingle(bytes, 0));
+

          
+
    Console.WriteLine();
+

          
+
    Console.WriteLine(BitConverter.ToString(BitConverter.GetBytes(42)));
+
    Console.WriteLine(BitConverter.ToString(BitConverter.GetBytes(1.0e+5)));
+
    Console.WriteLine(BitConverter.ToString(BitConverter.GetBytes(double.PositiveInfinity)));
+
    Console.WriteLine(BitConverter.ToString(BitConverter.GetBytes('あ')));
+
  }
+
}
 
}}
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim bytes() As Byte = New byte() {&hFF, &hFF, &h80, &h00}
+

          
+
    Console.WriteLine(BitConverter.ToString(bytes, 0))
+
    Console.WriteLine("{0}   0x{0:X8}", BitConverter.ToInt32(bytes, 0))
+
    Console.WriteLine("{0}   0x{0:X4}", BitConverter.ToInt16(bytes, 0))
+
    Console.WriteLine("{0}   0x{0:X4}", BitConverter.ToInt16(bytes, 2))
+
    Console.WriteLine(BitConverter.ToSingle(bytes, 0))
+

          
+
    Console.WriteLine()
+

          
+
    Console.WriteLine(BitConverter.ToString(BitConverter.GetBytes(42)))
+
    Console.WriteLine(BitConverter.ToString(BitConverter.GetBytes(1.0e+5)))
+
    Console.WriteLine(BitConverter.ToString(BitConverter.GetBytes(double.PositiveInfinity)))
+
    Console.WriteLine(BitConverter.ToString(BitConverter.GetBytes("あ"c)))
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
 

        

        
~
#prompt{{
暗黙的なキャストを許可したため、47・48行目の様な直接的な代入ができるようになりました。 ただ、hexの値の出力結果を見て「変だ、バグじゃないのか」と思われるかもしれませんが、これは50行目が呼び出される時点でhexが暗黙的にintにキャストされるためなのでバグではありません。 ただ、仕様としてはいまいち納得がいくものではないので、暗黙的なキャストを使う場合には思わぬ結果をもたらす可能性がある点に注意する必要があるといえます。
+
FF-FF-80-00
+
8454143   0x0080FFFF
+
-1   0xFFFF
+
128   0x0080
+
1.184678E-38
+

          
+
2A-00-00-00
+
00-00-00-00-00-6A-F8-40
+
00-00-00-00-00-00-F0-7F
+
42-30
+
}}
 

        

        
~
リファレンスでは明記されていませんが、結果として得られるバイト表現や変換結果は実行している環境のエンディアンなどにより変わると思われます。 現在実行している環境のエンディアンを調べるには、&msdn(netfx,member,System.BitConverter.IsLittleEndian){BitConverter.IsLittleEndianプロパティ};を参照します。 また、&msdn(netfx,type,System.Net.IPAddress){IPAddressクラス};の&msdn(netfx,method,System.Net.IPAddress.NetworkToHostOrder){NetworkToHostOrderメソッド};を使うことで整数型の値をネットワークバイトオーダー(ビッグエンディアン)からホストバイトオーダーに、&msdn(netfx,method,System.Net.IPAddress.HostToNetworkOrder){HostToNetworkOrderメソッド};を使うことでホストバイトオーダーからネットワークバイトオーダーに変換することが出来ます。
*構造体型同士の変換
-
前の例ではint型と独自に作成した構造体型同士の変換を定義しました。 続いて、構造体型同士の変換を定義してみます。 この例で使用する構造体は、角度の大きさをdouble型で保持し、度を単位として解釈するDegree型と、同じくラジアンを単位として解釈する Radian型を用いることにします。 また、これらの型はdouble型からのキャストも定義されています。 ただ、Degree・Radianから doubleへのキャストが定義されていないので、その場合はAngleメンバを使わなければなりません。 さらに、先ほどの例を見てわかるとおり、暗黙的なキャストは時に危険性をはらんでいるので、ここでは安全のため明示的なキャストのみを定義しています。
 

        

        
~
#tabpage(C#)
#code(cs,構造体型同士の変換){{
+
#code(cs){{
 
using System;
using System;
+
using System.Net;
 

        

        
~
class Sample
namespace TypeConversion
 
{
{
+
  static void Main()
+
  {
+
    Console.WriteLine("IsLittleEndian: {0}", BitConverter.IsLittleEndian);
+

          
+
    Console.WriteLine("NetworkToHostOrder");
+
    Console.WriteLine("{0:X8} => {1:X8}", 16, IPAddress.NetworkToHostOrder(16));
+
    Console.WriteLine("{0:X8} => {1:X8}", -256, IPAddress.NetworkToHostOrder(-256));
+
    Console.WriteLine("HostToNetworkOrder");
+
    Console.WriteLine("{0:X8} => {1:X8}", 16, IPAddress.HostToNetworkOrder(16));
+
    Console.WriteLine("{0:X8} => {1:X8}", -256, IPAddress.HostToNetworkOrder(-256));
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Net
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Console.WriteLine("IsLittleEndian: {0}", BitConverter.IsLittleEndian)
+

          
+
    Console.WriteLine("NetworkToHostOrder")
+
    Console.WriteLine("{0:X8} => {1:X8}", 16, IPAddress.NetworkToHostOrder(16))
+
    Console.WriteLine("{0:X8} => {1:X8}", -256, IPAddress.NetworkToHostOrder(-256))
+
    Console.WriteLine("HostToNetworkOrder")
+
    Console.WriteLine("{0:X8} => {1:X8}", 16, IPAddress.HostToNetworkOrder(16))
+
    Console.WriteLine("{0:X8} => {1:X8}", -256, IPAddress.HostToNetworkOrder(-256))
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
 

        

        
~
#prompt{{
    struct Degree
~
IsLittleEndian: True
    {
+
NetworkToHostOrder
+
00000010 => 10000000
+
FFFFFF00 => 00FFFFFF
+
HostToNetworkOrder
+
00000010 => 10000000
+
FFFFFF00 => 00FFFFFF
+
}}
 

        

        
~
***文字列とバイト配列への/からの変換
        public static double RadianToDegreeRate = 180.0 / Math.PI;
+
&msdn(netfx,type,System.Text.Encoding){Encodingクラス};を使うことで、任意の文字コードを用いて文字列とバイト配列の変換を行うことが出来ます。 &msdn(netfx,method,System.Text.Encoding.GetBytes){GetBytesメソッド};で文字列からバイト配列、&msdn(netfx,method,System.Text.Encoding.GetString){GetStringメソッド};でバイト配列から文字列に変換できます。
 

        

        
~
#tabpage(C#)
        public double Angle;
+
#code(cs){{
+
using System;
+
using System.Text;
 

        

        
~
class Sample
        // doubleを引数にとるコンストラクタ
~
{
        public Degree( double angle )
~
  static void Main()
        {
~
  {
            Angle = angle;
~
    Console.WriteLine(BitConverter.ToString(Encoding.ASCII.GetBytes("ABC")));
        }
~
    Console.WriteLine(BitConverter.ToString(Encoding.UTF8.GetBytes("あいう")));

          
~
    Console.WriteLine(BitConverter.ToString(Encoding.GetEncoding(932).GetBytes("漢字")));
        // Radianを引数にとるコンストラクタ
~

          
        public Degree( Radian angle )
~
    Console.WriteLine(Encoding.ASCII.GetString(new byte[] {0x41, 0x42, 0x43}));
        {
~
    Console.WriteLine(Encoding.UTF8.GetString(new byte[] {0xE3, 0x81, 0x82, 0xE3, 0x81, 0x84, 0xE3, 0x81, 0x86}));
            Angle = ((Degree)angle).Angle;
~
    Console.WriteLine(Encoding.GetEncoding(932).GetString(new byte[] {0x8A, 0xBF, 0x8E, 0x9A}));
        }
~
  }

          
~
}
        // Radian から Degree
~
}}
        public static explicit operator Degree( Radian angle )
~
#tabpage(VB)
        {
~
#code(vb){{
            return new Degree( angle.Angle * RadianToDegreeRate );
~
Imports System
        }
~
Imports System.Text

          
~

          
        // double から Degree
~
Class Sample
        public static explicit operator Degree( double angle )
~
  Shared Sub Main()
        {
~
    Console.WriteLine(BitConverter.ToString(Encoding.ASCII.GetBytes("ABC")))
            return new Degree( angle );
~
    Console.WriteLine(BitConverter.ToString(Encoding.UTF8.GetBytes("あいう")))
        }
~
    Console.WriteLine(BitConverter.ToString(Encoding.GetEncoding(932).GetBytes("漢字")))

          
~

          
        // Object.ToString() をオーバーライド
~
    Console.WriteLine(Encoding.ASCII.GetString(New Byte() {&h41, &h42, &h43}))
        public override string ToString()
~
    Console.WriteLine(Encoding.UTF8.GetString(New Byte() {&hE3, &h81, &h82, &hE3, &h81, &h84, &hE3, &h81, &h86}))
        {
~
    Console.WriteLine(Encoding.GetEncoding(932).GetString(New Byte() {&h8A, &hBF, &h8E, &h9A}))
            return Angle.ToString("F4") + " [Degree]";
~
  End Sub
        }
+
End Class
+
}}
+
#tabpage-end
 

        

        
~
#prompt{{
    }
+
41-42-43
+
E3-81-82-E3-81-84-E3-81-86
+
8A-BF-8E-9A
+
ABC
+
あいう
+
漢字
+
}}
 

        

        
~
**基本型間の変換
    struct Radian
~
***Convertクラス
    {
+
&msdn(netfx,method,System.Convert){Convertクラス};には、基本型間の変換を行うメソッドが用意されています。 これらのメソッドによる変換の結果は、キャストによる変換や、基本型のParseメソッドやToStringメソッドを直接呼び出す場合と概ね同じであるため、直接使う機会はあまりありません。 実数型から整数型への変換では、最近接偶数への丸め(MidpointRounding.ToEven)が行われます。
+

          
+
|*基本型間の変換が出来るメソッド
+
|~メソッド|~動作|h
+
|&msdn(netfx,method,System.Convert.ToByte){ToByte};|文字列からByteへの変換|
+
|&msdn(netfx,method,System.Convert.ToChar){ToChar};|文字列からCharへの変換|
+
|&msdn(netfx,method,System.Convert.ToInt16){ToInt16};|文字列からInt16への変換|
+
|&msdn(netfx,method,System.Convert.ToInt32){ToInt32};|文字列からInt32への変換|
+
|&msdn(netfx,method,System.Convert.ToInt64){ToInt64};|文字列からInt64への変換|
+
|&msdn(netfx,method,System.Convert.ToSByte){ToSByte};|文字列からSByteへの変換|
+
|&msdn(netfx,method,System.Convert.ToUInt16){ToUInt16};|文字列からUInt16への変換|
+
|&msdn(netfx,method,System.Convert.ToUInt32){ToUInt32};|文字列からUInt23への変換|
+
|&msdn(netfx,method,System.Convert.ToUInt64){ToUInt64};|文字列からUInt64への変換|
+
|&msdn(netfx,method,System.Convert.ToSingle){ToSingle};|文字列からSingleへの変換|
+
|&msdn(netfx,method,System.Convert.ToDouble){ToDouble};|文字列からDoubleへの変換|
+
|&msdn(netfx,method,System.Convert.ToDecimal){ToDecimal};|文字列からDecimalへの変換|
+
|&msdn(netfx,method,System.Convert.ToBoolean){ToBoolean};|文字列からBooleanへの変換|
+
|&msdn(netfx,method,System.Convert.ToDateTime){ToDateTime};|文字列からDateTimeへの変換|
+
|&msdn(netfx,method,System.Convert.ToString){ToString};|文字列からStringへの変換|
 

        

        
~
このメソッドは、変換できない形式の場合は&msdn(netfx,type,System.FormatException){FormatException};、変換した値が型の最大値・最小値を超える場合は&msdn(netfx,type,System.OverflowException){OverflowException};、変換が定義されていない場合(DateTimeからInt32など)は&msdn(netfx,type,System.InvalidCastException){InvalidCastException};をスローします。
        public static double DegreeToRadianRate = Math.PI / 180.0;
 

        

        
~
また、Convertクラスにはobjectから任意の型に変換する&msdn(netfx,method,System.Convert.ChangeType){ChangeType};メソッドも用意されています。 このメソッドは変換後の型を&msdn(netfx,type,System.Type){Typeクラス};または&msdn(netfx,type,System.TypeCode){TypeCode列挙型};で指定することが出来ます。 変換される型は[[IConvertibleインターフェイス>#IConvertible]]を実装している必要があります。 当然、変換できない型の場合にはInvalidCastExceptionがスローされます。
        public double Angle;
 

        

        
~
以下の例は、Convertクラスのメソッドを使って基本型の型変換を行ったものです。
        // doubleを引数にとるコンストラクタ
-
        public Radian( double angle )
-
        {
-
            Angle = angle;
-
        }
-

          
-
        // Degreeを引数にとるコンストラクタ
-
        public Radian( Degree angle )
-
        {
-
            Angle = ((Radian)angle).Angle;
-
        }
-

          
-
        // Degree から Radian
-
        public static explicit operator Radian( Degree angle )
-
        {
-
            return new Radian( angle.Angle * DegreeToRadianRate );
-
        }
-

          
-
        // double から Radian
-
        public static explicit operator Radian( double angle )
-
        {
-
            return new Radian( angle );
-
        }
-

          
-
        // Object.ToString() をオーバーライド
-
        public override string ToString()
-
        {
-
            return Angle.ToString("F4") + " [Radian]";
-
        }
 

        

        
~
#tabpage(C#)
    }
+
#code(cs){{
+
using System;
 

        

        
~
class Sample
    
~
{
    class Class1
~
  static void Main()
    {
~
  {
        [STAThread]
~
    int i1 = Convert.ToInt32(3.5);
        static void Main(string[] args)
~
    int i2 = Convert.ToInt32(4.5);
        {
+

          
+
    Console.WriteLine(i1);
+
    Console.WriteLine(i2);
+

          
+
    double d = Convert.ToDouble(16);
+

          
+
    Console.WriteLine(d);
+

          
+
    object o1 = Convert.ChangeType("3.14", typeof(double));
+
    object o2 = Convert.ChangeType("3.14", TypeCode.Double);
+
    object o3 = Convert.ChangeType("72", typeof(int));
+
    object o4 = Convert.ChangeType("72", TypeCode.Int32);
+

          
+
    Console.WriteLine("{0} ({1})", o1, o1.GetType());
+
    Console.WriteLine("{0} ({1})", o2, o2.GetType());
+
    Console.WriteLine("{0} ({1})", o3, o3.GetType());
+
    Console.WriteLine("{0} ({1})", o4, o4.GetType());
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim i1 As Integer = Convert.ToInt32(3.5)
+
    Dim i2 As Integer = Convert.ToInt32(4.5)
+

          
+
    Console.WriteLine(i1)
+
    Console.WriteLine(i2)
+

          
+
    Dim d As Double = Convert.ToDouble(16)
+

          
+
    Console.WriteLine(d)
+

          
+
    Dim o1 As Object = Convert.ChangeType("3.14", GetType(Double))
+
    Dim o2 As Object = Convert.ChangeType("3.14", TypeCode.Double)
+
    Dim o3 As Object = Convert.ChangeType("72", GetType(Integer))
+
    Dim o4 As Object = Convert.ChangeType("72", TypeCode.Int32)
+

          
+
    Console.WriteLine("{0} ({1})", o1, o1.GetType())
+
    Console.WriteLine("{0} ({1})", o2, o2.GetType())
+
    Console.WriteLine("{0} ({1})", o3, o3.GetType())
+
    Console.WriteLine("{0} ({1})", o4, o4.GetType())
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
 

        

        
~
#prompt{{
            Radian rad1 = (Radian)( Math.PI * 0.5 );
~
4
            Degree deg1 = (Degree)rad1;
+
4
+
16
+
3.14 (System.Double)
+
3.14 (System.Double)
+
72 (System.Int32)
+
72 (System.Int32)
+
}}
 

        

        
~
***XmlConvertクラス
            Console.WriteLine( rad1 );
~
&msdn(netfx,method,System.Xml.XmlConvert){XmlConvertクラス};は本来、XMLスキーマのデータ型との変換を行うために用意されてるものですが、Convertクラスではサポートされていない&msdn(netfx,method,System.Guid){Guid};、&msdn(netfx,method,System.TimeSpan){TimeSpan};、&msdn(netfx,method,System.DateTimeOffset){DateTimeOffset};と文字列との変換を行うことが出来ます。
            Console.WriteLine( deg1 );
 

        

        
~
#googleadunit
            Degree deg2 = (Degree)45.0;
-
            Radian rad2 = (Radian)deg2;
 

        

        
~
----
            Console.WriteLine( rad2 );
-
            Console.WriteLine( deg2 );
 

        

        
~
*ユーザ定義の型変換
        }
~
ここでは複素数を定義する次のような構造体を使って、ユーザー定義の型変換について見ていきます。
    }
+

          
+
#tabpage(C#)
+
#code(cs){{
+
struct Complex
+
{
+
  public double Real; // 実部
+
  public double Imaginary; // 虚部
+

          
+
  public Complex(double real, double imaginary)
+
    : this()
+
  {
+
    this.Real = real;
+
    this.Imaginary = imaginary;
+
  }
 
}
}
 
}}
}}
+
#tabpage(VB)
+
#code(vb){{
+
Structure Complex
+
  Public Real As Double ' 実部
+
  Public Imaginary As Double ' 虚部
+

          
+
  Public Sub New(ByVal real As Double, ByVal imaginary As Double)
+
    MyClass.Real = real
+
    MyClass.Imaginary = imaginary
+
  End Sub
+
End Structure
+
}}
+
#tabpage-end
+

          
+
参考までに、.NET Framework 4より&msdn(netfx,method,System.Numerics.Complex){System.Numerics.Complex構造体};が使えるようになっています。
 

        

        
~
**文字列への変換
#prompt(実行結果){{
~
***ToString
1.5708 [Radian]
~
文字列への変換をサポートするためには、ToStringをオーバーライドすることが出来ます。
90.0000 [Degree]
~

          
0.7854 [Radian]
~
#tabpage(C#)
45.0000 [Degree]
~
#code(cs){{
Press any key to continue
+
using System;
+

          
+
struct Complex
+
{
+
  public double Real; // 実部
+
  public double Imaginary; // 虚部
+

          
+
  public Complex(double real, double imaginary)
+
    : this()
+
  {
+
    this.Real = real;
+
    this.Imaginary = imaginary;
+
  }
+

          
+
  // ToStringのオーバーライド
+
  public override string ToString()
+
  {
+
    return string.Format("({0:F4}, {1:F4})", Real, Imaginary);
+
  }
+
}
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    Complex c1 = new Complex(-1.414, 1.414);
+
    Complex c2 = new Complex( 3.000, 4.000);
+

          
+
    Console.WriteLine("{0} {1}", c1.ToString(), c1);
+
    Console.WriteLine("{0} {1}", c2.ToString(), c2);
+
  }
+
}
 
}}
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Text
+

          
+
Structure Complex
+
  Public Real As Double ' 実部
+
  Public Imaginary As Double ' 虚部
+

          
+
  Public Sub New(ByVal real As Double, ByVal imaginary As Double)
+
    MyClass.Real = real
+
    MyClass.Imaginary = imaginary
+
  End Sub
+

          
+
  ' ToStringのオーバーライド
+
  Public Overrides Function ToString() As String
+
    Return string.Format("({0:F4}, {1:F4})", Real, Imaginary)
+
  End Function
+
End Structure
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim c1 As New Complex(-1.414, 1.414)
+
    Dim c2 As New Complex( 3.000, 4.000)
+

          
+
    Console.WriteLine("{0} {1}", c1.ToString(), c1)
+
    Console.WriteLine("{0} {1}", c2.ToString(), c2)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
(-1.4140, 1.4140) (-1.4140, 1.4140)
+
(3.0000, 4.0000) (3.0000, 4.0000)
+
}}
+

          
+
もちろん、次の例ように妥当な理由がある場合は文字列化専用のメソッドを用意しToStringメソッドをオーバーライドしないという方法を採ることもできます。 ただ、すべてのユーザー定義型は&msdn(netfx,type,System.Object){Object};を継承していて、ランタイムにより文字列化される際に&msdn(netfx,method,System.Object.ToString){Object.ToStringメソッド};が呼び出されることがあるため、このメソッドをオーバーライドすることで文字列化される際の動作を定義しておいた方がよいでしょう。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+

          
+
struct Complex
+
{
+
  public double Real; // 実部
+
  public double Imaginary; // 虚部
 

        

        
~
  public Complex(double real, double imaginary)
Main()メソッドでの流れを簡単に説明すると、まず91行目でrad1を宣言しπ/2ラジアンを代入します。 Math.PI * 0.5がπ/2を意味し、これはdouble型なので明示的なキャストにより、Radian型にキャストしてから代入します。 続いて次の行ではたった今作成したrad1をDegree型に変換してdeg1に代入します。 これらの値を表示するためのコードが94・95行目ですが、その結果は見ての通りです。 π/2ラジアンは90.0度なので、想定していたとおりの結果を得ることができました。
+
    : this()
+
  {
+
    this.Real = real;
+
    this.Imaginary = imaginary;
+
  }
+

          
+
  // 文字列化のためのメソッド
+
  public string ConvertToString()
+
  {
+
    return string.Format("({0:F4}, {1:F4})", Real, Imaginary);
+
  }
+
}
 

        

        
~
class Sample
さらに次は逆の変換をしてみます。 まず97行目でdeg2に45.0度を代入します。 さらにその値をRadian型のrad2に代入します。 その結果も見ての通りで、45.0度はπ/4ラジアン、すなわち約0.785ラジアンとなります。
+
{
+
  static void Main()
+
  {
+
    Complex c1 = new Complex(-1.414, 1.414);
+
    Complex c2 = new Complex( 3.000, 4.000);
+

          
+
    Console.WriteLine("{0} {1}", c1.ConvertToString(), c1);
+
    Console.WriteLine("{0} {1}", c2.ConvertToString(), c2);
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+

          
+
Structure Complex
+
  Public Real As Double ' 実部
+
  Public Imaginary As Double ' 虚部
+

          
+
  Public Sub New(ByVal real As Double, ByVal imaginary As Double)
+
    MyClass.Real = real
+
    MyClass.Imaginary = imaginary
+
  End Sub
+

          
+
  ' 文字列化のためのメソッド
+
  Public Function ConvertToString() As String
+
    Return string.Format("({0:F4}, {1:F4})", Real, Imaginary)
+
  End Function
+
End Structure
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim c1 As New Complex(-1.414, 1.414)
+
    Dim c2 As New Complex( 3.000, 4.000)
+

          
+
    Console.WriteLine("{0} {1}", c1.ConvertToString(), c1)
+
    Console.WriteLine("{0} {1}", c2.ConvertToString(), c2)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
 

        

        
~
#prompt{{
*型変換演算子の定義箇所
~
(-1.4140, 1.4140) Complex
ここまででは型変換演算子の定義箇所についてあまり意識しませんでした。 が、実際にもほとんど意識する必要はありません。 例えば、前の例のように型A・型 B間変換を定義する際に、必ずしも型Aから型Bへのキャストは型Aで行わなければならないわけではありません。 型A・型Bさえ定義されていれば、型Aから型B、型Bから型Aの両方の変換演算子を型Aに定義してしまっても全く問題ありません。
+
(3.0000, 4.0000) Complex
+
}}
 

        

        
~
***IFormattable
次の例は、双方向の型変換を一つの型の中で定義してしまった例です。 結果的にはいずれの方向にもキャスト可能になっているのに注目して下さい。 また、些細な変化ですが、今回はクラス型で型変換演算子を定義していますが、方法は構造体の場合と全く変わりありません。
+
&msdn(netfx,method,System.IFormattable){IFormattableインターフェイス};を実装することで、書式を指定した文字列化をサポートすることができます。 また、書式だけでなくカルチャを考慮した文字列化のサポートもIFormattableインターフェイスを用いて実装出来ます。 IFormattableについての詳細は[[programming/netfx2/string_formatting]]で解説しています。
 

        

        
~
#tabpage(C#)
#code(cs,型変換演算子の定義箇所){{
+
#code(cs){{
 
using System;
using System;
 

        

        
~
struct Complex : IFormattable
namespace TypeConversion
 
{
{
+
  public double Real; // 実部
+
  public double Imaginary; // 虚部
 

        

        
~
  public Complex(double real, double imaginary)
    class TypeA
+
    : this()
+
  {
+
    this.Real = real;
+
    this.Imaginary = imaginary;
+
  }
+

          
+
  // Object.ToStringのオーバーライド
+
  public override string ToString()
+
  {
+
    return ToString(null, null);
+
  }
+

          
+
  // IFormattable.ToStringの実装
+
  public string ToString(string format, IFormatProvider formatProvider)
+
  {
+
    if (format == "P")
 
    {
    {
~
      // 極座標表示に書式化
        public string Value;
+
      double r = Math.Sqrt(Real * Real + Imaginary * Imaginary);
+
      double t = Math.Atan2(Imaginary, Real) / Math.PI;
 

        

        
~
      return string.Format(formatProvider, "{0:F4}∠{1:F4}π", r, t);
        public TypeA( string Value )
-
        {
-
            this.Value = Value;
-
        }
-

          
-
        public override string ToString()
-
        {
-
            return "One of TypeA said, \"" + Value + "\"";
-
        }
 
    }
    }
~
    else
    
-
    class TypeB
 
    {
    {
~
      // ガウス平面座標表示に書式化
        public string Value;
+
      return string.Format(formatProvider, "({0:F4}, {1:F4})", Real, Imaginary);
+
    }
+
  }
+
}
 

        

        
~
class Sample
        public TypeB( string Value )
~
{
        {
~
  static void Main()
            this.Value = Value;
~
  {
        }
~
    Complex c1 = new Complex(-1.414, 1.414);

          
~
    Complex c2 = new Complex( 3.000, 4.000);
        // TypeA から TypeBへのキャスト
~

          
        public static explicit operator TypeB( TypeA a )
~
    Console.WriteLine("{0} {0:P}", c1);
        {
~
    Console.WriteLine("{0} {0:P}", c2);
            return new TypeB( a.Value );
~
  }
        }
~
}

          
~
}}
        // TypeB から TypeAへのキャスト
~
#tabpage(VB)
        public static explicit operator TypeA( TypeB b )
~
#code(vb){{
        {
~
Imports System
            return new TypeA( b.Value );
~

          
        }
~
Structure Complex

          
~
  Implements IFormattable
        public override string ToString()
~

          
        {
~
  Public Real As Double ' 実部
            return "One of TypeB said, \"" + Value + "\"";
~
  Public Imaginary As Double ' 虚部
        }
+

          
+
  Public Sub New(ByVal real As Double, ByVal imaginary As Double)
+
    MyClass.Real = real
+
    MyClass.Imaginary = imaginary
+
  End Sub
+

          
+
  ' Object.ToStringのオーバーライド
+
  Public Overrides Function ToString() As String
+
    Return ToString(Nothing, Nothing)
+
  End Function
+

          
+
  ' IFormattable.ToStringの実装
+
  Public Function ToString(ByVal format As String, ByVal formatProvider As IFormatProvider) As String Implements IFormattable.ToString
+
    If format = "P" Then
+
      ' 極座標表示に書式化
+
      Dim r As Double = Math.Sqrt(Real * Real + Imaginary * Imaginary)
+
      Dim t As Double = Math.Atan2(Imaginary, Real) / Math.PI
+

          
+
      Return String.Format(formatProvider, "{0:F4}∠{1:F4}π", r, t)
+
    Else
+
      ' ガウス平面座標表示に書式化
+
      Return String.Format(formatProvider, "({0:F4}, {1:F4})", Real, Imaginary)
+
    End If
+
  End Function
+
End Structure
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim c1 As New Complex(-1.414, 1.414)
+
    Dim c2 As New Complex( 3.000, 4.000)
+

          
+
    Console.WriteLine("{0} {0:P}", c1)
+
    Console.WriteLine("{0} {0:P}", c2)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
(-1.4140, 1.4140) 1.9997∠0.7500π
+
(3.0000, 4.0000) 5.0000∠0.2952π
+
}}
+

          
+
**基本型への変換
+
***ToXXX
+
他の基本型への変換を定義するもっとも簡単な方法は、文字列化の際と同様、目的の型への変換用のメソッドを用意することです。 次の例では、Complex型をDouble型の値として返すメソッドToDoubleを用意し、複素数の絶対値を返すようにしています。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+

          
+
struct Complex
+
{
+
  public double Real; // 実部
+
  public double Imaginary; // 虚部
+

          
+
  public Complex(double real, double imaginary)
+
    : this()
+
  {
+
    this.Real = real;
+
    this.Imaginary = imaginary;
+
  }
+

          
+
  public double ToDouble()
+
  {
+
    return Math.Sqrt(Real * Real + Imaginary * Imaginary);
+
  }
+
}
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    Complex c1 = new Complex(-1.414, 1.414);
+
    Complex c2 = new Complex( 3.000, 4.000);
+

          
+
    double d1 = c1.ToDouble();
+
    double d2 = c2.ToDouble();
+

          
+
    Console.WriteLine(d1);
+
    Console.WriteLine(d2);
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+

          
+
Structure Complex
+
  Public Real As Double ' 実部
+
  Public Imaginary As Double ' 虚部
+

          
+
  Public Sub New(ByVal real As Double, ByVal imaginary As Double)
+
    MyClass.Real = real
+
    MyClass.Imaginary = imaginary
+
  End Sub
+

          
+
  Public Function ToDouble() As Double
+
    Return Math.Sqrt(Real * Real + Imaginary * Imaginary)
+
  End Function
+
End Structure
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim c1 As New Complex(-1.414, 1.414)
+
    Dim c2 As New Complex( 3.000, 4.000)
+

          
+
    Dim d1 As Double = c1.ToDouble()
+
    Dim d2 As Double = c2.ToDouble()
+

          
+
    Console.WriteLine(d1)
+
    Console.WriteLine(d2)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
1.99969797719556
+
5
+
}}
+

          
+
ただ、このようなメソッドを用意しても、Convertクラスを使った変換などが出来るようになるわけではありません。 次のコードを実行すると、InvalidCastExceptionがスローされます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+

          
+
struct Complex
+
{
+
  public double Real; // 実部
+
  public double Imaginary; // 虚部
+

          
+
  public Complex(double real, double imaginary)
+
    : this()
+
  {
+
    this.Real = real;
+
    this.Imaginary = imaginary;
+
  }
+

          
+
  public double ToDouble()
+
  {
+
    return Math.Sqrt(Real * Real + Imaginary * Imaginary);
+
  }
+
}
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    Complex c1 = new Complex(-1.414, 1.414);
+
    Complex c2 = new Complex( 3.000, 4.000);
+

          
+
    double d1 = Convert.ToDouble(c1);
+
    double d2 = Convert.ToDouble(c2);
+

          
+
    Console.WriteLine(d1);
+
    Console.WriteLine(d2);
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+

          
+
Structure Complex
+
  Public Real As Double ' 実部
+
  Public Imaginary As Double ' 虚部
+

          
+
  Public Sub New(ByVal real As Double, ByVal imaginary As Double)
+
    MyClass.Real = real
+
    MyClass.Imaginary = imaginary
+
  End Sub
+

          
+
  Public Function ToDouble() As Double
+
    Return Math.Sqrt(Real * Real + Imaginary * Imaginary)
+
  End Function
+
End Structure
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim c1 As New Complex(-1.414, 1.414)
+
    Dim c2 As New Complex( 3.000, 4.000)
+

          
+
    Dim d1 As Double = Convert.ToDouble(c1)
+
    Dim d2 As Double = Convert.ToDouble(c2)
+

          
+
    Console.WriteLine(d1)
+
    Console.WriteLine(d2)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
ハンドルされていない例外: System.InvalidCastException: 型 'Complex' のオブジェクトを型 'System.IConvertible' にキャストできません。
+
   場所 System.Convert.ToDouble(Object value)
+
   場所 Sample.Main()
+
}}
+

          
+
***&aname(IConvertible){IConvertible};
+
Convertクラスを用いた型変換をサポートするには、&msdn(netfx,type,System.IConvertible){IConvertibleインターフェイス};を実装しなければなりません。 このインターフェイスには、他の基本型への変換を行うためのメソッドが用意されています。 これらのメソッドでは、変換を定義できる場合は変換結果を返し、変換を定義できない場合はInvalidCastExceptionをスローするようにします。
+

          
+
以下はIConvertibleを実装する例です。 この例のComplex型では、IConvertibleを次のように実装しています。
+
-Double型への変換では、Complex型の表す複素数の絶対値を返す
+
-その他の実数型・整数型への変換では、Complex型の表す複素数の絶対値を目的の型に変換して返す
+
-Boolean型の変換では、実部・虚部ともに0の場合はfalse、そうでなければtrueを返す
+
-String型への変換では、ガウス平面座標表示に書式化した文字列を返す
+
-&msdn(netfx,type,System.Drawing.PointF){System.Drawing.PointF型};への変換をサポートする
+
-それ以外の型への変換はサポートしない(InvalidCastExceptionをスローする)
+
-IConvertible.ToString以外は直接呼び出せないように明示的な実装にする
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Drawing;
+

          
+
struct Complex : IConvertible
+
{
+
  public double Real; // 実部
+
  public double Imaginary; // 虚部
+

          
+
  public Complex(double real, double imaginary)
+
    : this()
+
  {
+
    this.Real = real;
+
    this.Imaginary = imaginary;
+
  }
+

          
+
  TypeCode IConvertible.GetTypeCode()
+
  {
+
    // ユーザ定義型であるTypeCode.Objectを返す
+
    return TypeCode.Object;
+
  }
+

          
+
  double IConvertible.ToDouble(IFormatProvider provider)
+
  {
+
    return Math.Sqrt(Real * Real + Imaginary * Imaginary);
+
  }
+

          
+
  float IConvertible.ToSingle(IFormatProvider provider)
+
  {
+
    return Convert.ToSingle((this as IConvertible).ToDouble(provider));
+
  }
+

          
+
  decimal IConvertible.ToDecimal(IFormatProvider provider)
+
  {
+
    return Convert.ToDecimal((this as IConvertible).ToDouble(provider));
+
  }
+

          
+
  byte IConvertible.ToByte(IFormatProvider provider)
+
  {
+
    return Convert.ToByte((this as IConvertible).ToDouble(provider));
+
  }
+

          
+
  short IConvertible.ToInt16(IFormatProvider provider)
+
  {
+
    return Convert.ToInt16((this as IConvertible).ToDouble(provider));
+
  }
+

          
+
  int IConvertible.ToInt32(IFormatProvider provider)
+
  {
+
    return Convert.ToInt32((this as IConvertible).ToDouble(provider));
+
  }
+

          
+
  long IConvertible.ToInt64(IFormatProvider provider)
+
  {
+
    return Convert.ToInt64((this as IConvertible).ToDouble(provider));
+
  }
+

          
+
  sbyte IConvertible.ToSByte(IFormatProvider provider)
+
  {
+
    return Convert.ToSByte((this as IConvertible).ToDouble(provider));
+
  }
+

          
+
  ushort IConvertible.ToUInt16(IFormatProvider provider)
+
  {
+
    return Convert.ToUInt16((this as IConvertible).ToDouble(provider));
+
  }
+

          
+
  uint IConvertible.ToUInt32(IFormatProvider provider)
+
  {
+
    return Convert.ToUInt32((this as IConvertible).ToDouble(provider));
+
  }
+

          
+
  ulong IConvertible.ToUInt64(IFormatProvider provider)
+
  {
+
    return Convert.ToUInt64((this as IConvertible).ToDouble(provider));
+
  }
+

          
+
  bool IConvertible.ToBoolean(IFormatProvider provider)
+
  {
+
    return (Real != 0.0 || Imaginary != 0.0);
+
  }
+

          
+
  public override string ToString()
+
  {
+
    // IConvertible.ToString(IFormatProvider)の結果を返す
+
    return ToString(null);
+
  }
+

          
+
  public string ToString(IFormatProvider provider)
+
  {
+
    return string.Format(provider, "({0:F4}, {1:F4})", Real, Imaginary);
+
  }
+

          
+
  object IConvertible.ToType(Type conversionType, IFormatProvider provider)
+
  {
+
    if (conversionType == typeof(PointF))
+
    {
+
      return new PointF(Convert.ToSingle(Real), Convert.ToSingle(Imaginary));
 
    }
    }
~
    else
    
-
    class Class1
 
    {
    {
~
      throw new InvalidCastException();
        [STAThread]
~
    }
        static void Main(string[] args)
~
  }
        {
+

          
+
  char IConvertible.ToChar(IFormatProvider provider)
+
  {
+
    throw new InvalidCastException();
+
  }
+

          
+
  DateTime IConvertible.ToDateTime(IFormatProvider provider)
+
  {
+
    throw new InvalidCastException();
+
  }
+
}
 

        

        
~
class Sample
            TypeA a;
~
{
            TypeB b;
+
  static void Main()
+
  {
+
    Complex c1 = new Complex(-1.414, 1.414);
+
    Complex c2 = new Complex( 3.000, 4.000);
 

        

        
+
    Console.WriteLine("ToString");
+
    Console.WriteLine("{0} {1} {2}", c1, c1.ToString(), Convert.ToString(c1));
+
    Console.WriteLine("{0} {1} {2}", c2, c2.ToString(), Convert.ToString(c2));
 

        

        
~
    double d1 = Convert.ToDouble(c1);
            a = (TypeA)( new TypeB( "I\'m a instance of TypeB." ) );
~
    double d2 = Convert.ToDouble(c2);
            b = (TypeB)( new TypeA( "I\'m a instance of TypeA." ) );
 

        

        
~
    Console.WriteLine("ToDouble");
            Console.WriteLine( a );
~
    Console.WriteLine("{0} => {1}", c1, d1);
            Console.WriteLine( b );
+
    Console.WriteLine("{0} => {1}", c2, d2);
+

          
+
    bool b1 = Convert.ToBoolean(c1);
+
    bool b2 = Convert.ToBoolean(c2);
+

          
+
    Console.WriteLine("ToBoolean");
+
    Console.WriteLine("{0} => {1}", c1, b1);
+
    Console.WriteLine("{0} => {1}", c2, b2);
+

          
+
    int i1 = Convert.ToInt32(c1);
+
    int i2 = Convert.ToInt32(c2);
+

          
+
    Console.WriteLine("ToInt32");
+
    Console.WriteLine("{0} => {1}", c1, i1);
+
    Console.WriteLine("{0} => {1}", c2, i2);
+

          
+
    float s1 = (float)Convert.ChangeType(c1, TypeCode.Single);
+
    float s2 = (float)Convert.ChangeType(c2, TypeCode.Single);
+

          
+
    Console.WriteLine("ChangeType TypeCode.Single");
+
    Console.WriteLine("{0} => {1}", c1, s1);
+
    Console.WriteLine("{0} => {1}", c2, s2);
+

          
+
    PointF p1 = (PointF)Convert.ChangeType(c1, typeof(PointF));
+
    PointF p2 = (PointF)Convert.ChangeType(c2, typeof(PointF));
+

          
+
    Console.WriteLine("ChangeType PointF");
+
    Console.WriteLine("{0} => {1}", c1, p1);
+
    Console.WriteLine("{0} => {1}", c2, p2);
+

          
+
    Console.WriteLine("ToDateTime");
+
    Console.WriteLine("{0} => {1}", c1, Convert.ToDateTime(c1));
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Drawing
+

          
+
Structure Complex
+
  Implements IConvertible
+

          
+
  Public Real As Double ' 実部
+
  Public Imaginary As Double ' 虚部
+

          
+
  Public Sub New(ByVal real As Double, ByVal imaginary As Double)
+
    MyClass.Real = real
+
    MyClass.Imaginary = imaginary
+
  End Sub
+

          
+
  Private Function GetTypeCode() As TypeCode Implements IConvertible.GetTypeCode
+
    ' ユーザ定義型であるTypeCode.Objectを返す
+
    Return TypeCode.Object
+
  End Function
+

          
+
  Private Function ToDouble(ByVal provider As IFormatProvider) As Double Implements IConvertible.ToDouble
+
    Return Math.Sqrt(Real * Real + Imaginary * Imaginary)
+
  End Function
+

          
+
  Private Function ToSingle(ByVal provider As IFormatProvider) As Single Implements IConvertible.ToSingle
+
    Return Convert.ToSingle(DirectCast(Me, IConvertible).ToDouble(provider))
+
  End Function
+

          
+
  Private Function ToDecimal(ByVal provider As IFormatProvider) As Decimal Implements IConvertible.ToDecimal
+
    Return Convert.ToDecimal(DirectCast(Me, IConvertible).ToDouble(provider))
+
  End Function
+

          
+
  Private Function ToByte(ByVal provider As IFormatProvider) As Byte Implements IConvertible.ToByte
+
    Return Convert.ToByte(DirectCast(Me, IConvertible).ToDouble(provider))
+
  End Function
+

          
+
  Private Function ToInt16(ByVal provider As IFormatProvider) As Short Implements IConvertible.ToInt16
+
    Return Convert.ToInt16(DirectCast(Me, IConvertible).ToDouble(provider))
+
  End Function
+

          
+
  Private Function ToInt32(ByVal provider As IFormatProvider) As Integer Implements IConvertible.ToInt32
+
    Return Convert.ToInt32(DirectCast(Me, IConvertible).ToDouble(provider))
+
  End Function
+

          
+
  Private Function ToInt64(ByVal provider As IFormatProvider) As Long Implements IConvertible.ToInt64
+
    Return Convert.ToInt64(DirectCast(Me, IConvertible).ToDouble(provider))
+
  End Function
+

          
+
  Private Function ToSByte(ByVal provider As IFormatProvider) As SByte Implements IConvertible.ToSByte
+
    Return Convert.ToSByte(DirectCast(Me, IConvertible).ToDouble(provider))
+
  End Function
+

          
+
  Private Function ToUInt16(ByVal provider As IFormatProvider) As UShort Implements IConvertible.ToUInt16
+
    Return Convert.ToUInt16(DirectCast(Me, IConvertible).ToDouble(provider))
+
  End Function
+

          
+
  Private Function ToUInt32(ByVal provider As IFormatProvider) As UInteger Implements IConvertible.ToUInt32
+
    Return Convert.ToUInt32(DirectCast(Me, IConvertible).ToDouble(provider))
+
  End Function
+

          
+
  Private Function ToUInt64(ByVal provider As IFormatProvider) As ULong Implements IConvertible.ToUInt64
+
    Return Convert.ToUInt64(DirectCast(Me, IConvertible).ToDouble(provider))
+
  End Function
+

          
+
  Private Function ToBoolean(ByVal provider As IFormatProvider) As Boolean Implements IConvertible.ToBoolean
+
    Return (Real <> 0.0 OrElse Imaginary <> 0.0)
+
  End Function
+

          
+
  Public Overloads Overrides Function ToString() As String
+
    ' IConvertible.ToString(IFormatProvider)の結果を返す
+
    Return ToString(Nothing)
+
  End Function
+

          
+
  Public Overloads Function ToString(ByVal provider As IFormatProvider) As String Implements IConvertible.ToString
+
    Return String.Format(provider, "({0:F4}, {1:F4})", Real, Imaginary)
+
  End Function
+

          
+
  Private Function ToType(ByVal conversionType As Type, ByVal provider As IFormatProvider) As Object Implements IConvertible.ToType
+
    If conversionType Is GetType(PointF) Then
+
      Return New PointF(Convert.ToSingle(Real), Convert.ToSingle(Imaginary))
+
    Else
+
      Throw New InvalidCastException()
+
    End If
+
  End Function
+

          
+
  Private Function ToChar(ByVal provider As IFormatProvider) As Char Implements IConvertible.ToChar
+
    Throw New InvalidCastException()
+
  End Function
+

          
+
  Private Function ToDateTime(ByVal provider As IFormatProvider) As DateTime Implements IConvertible.ToDateTime
+
    Throw New InvalidCastException()
+
  End Function
+
End Structure
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim c1 As New Complex(-1.414, 1.414)
+
    Dim c2 As New Complex( 3.000, 4.000)
+

          
+
    Console.WriteLine("ToString")
+
    Console.WriteLine("{0} {1} {2}", c1, c1.ToString(), Convert.ToString(c1))
+
    Console.WriteLine("{0} {1} {2}", c2, c2.ToString(), Convert.ToString(c2))
+

          
+
    Dim d1 As Double = Convert.ToDouble(c1)
+
    Dim d2 As Double = Convert.ToDouble(c2)
+

          
+
    Console.WriteLine("ToDouble")
+
    Console.WriteLine("{0} => {1}", c1, d1)
+
    Console.WriteLine("{0} => {1}", c2, d2)
+

          
+
    Dim b1 As Boolean = Convert.ToBoolean(c1)
+
    Dim b2 As Boolean = Convert.ToBoolean(c2)
+

          
+
    Console.WriteLine("ToBoolean")
+
    Console.WriteLine("{0} => {1}", c1, b1)
+
    Console.WriteLine("{0} => {1}", c2, b2)
+

          
+
    Dim i1 As Integer = Convert.ToInt32(c1)
+
    Dim i2 As Integer = Convert.ToInt32(c2)
+

          
+
    Console.WriteLine("ToInt32")
+
    Console.WriteLine("{0} => {1}", c1, i1)
+
    Console.WriteLine("{0} => {1}", c2, i2)
+

          
+
    Dim s1 As Single = DirectCast(Convert.ChangeType(c1, TypeCode.Single), Single)
+
    Dim s2 As Single = DirectCast(Convert.ChangeType(c2, TypeCode.Single), Single)
+

          
+
    Console.WriteLine("ChangeType TypeCode.Single")
+
    Console.WriteLine("{0} => {1}", c1, s1)
+
    Console.WriteLine("{0} => {1}", c2, s2)
+

          
+
    Dim p1 As PointF = DirectCast(Convert.ChangeType(c1, GetType(PointF)), PointF)
+
    Dim p2 As PointF = DirectCast(Convert.ChangeType(c2, GetType(PointF)), PointF)
+

          
+
    Console.WriteLine("ChangeType PointF")
+
    Console.WriteLine("{0} => {1}", c1, p1)
+
    Console.WriteLine("{0} => {1}", c2, p2)
+

          
+
    Console.WriteLine("ToDateTime")
+
    Console.WriteLine("{0} => {1}", c1, Convert.ToDateTime(c1))
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
ToString
+
(-1.4140, 1.4140) (-1.4140, 1.4140) (-1.4140, 1.4140)
+
(3.0000, 4.0000) (3.0000, 4.0000) (3.0000, 4.0000)
+
ToDouble
+
(-1.4140, 1.4140) => 1.99969797719556
+
(3.0000, 4.0000) => 5
+
ToBoolean
+
(-1.4140, 1.4140) => True
+
(3.0000, 4.0000) => True
+
ToInt32
+
(-1.4140, 1.4140) => 2
+
(3.0000, 4.0000) => 5
+
ChangeType TypeCode.Single
+
(-1.4140, 1.4140) => 1.999698
+
(3.0000, 4.0000) => 5
+
ChangeType PointF
+
(-1.4140, 1.4140) => {X=-1.414, Y=1.414}
+
(3.0000, 4.0000) => {X=3, Y=4}
+
ToDateTime
+

          
+
ハンドルされていない例外: System.InvalidCastException: 指定されたキャストは有効ではありません。
+
   場所 Complex.System.IConvertible.ToDateTime(IFormatProvider provider)
+
   場所 System.Convert.ToDateTime(Object value)
+
   場所 Sample.Main()
+
}}
+

          
+
**暗黙的・明示的な型変換
+
ここまでではメソッドやインターフェイスを通した型変換を行う例を解説してきましたが、型変換演算子をオーバーロード(多重定義)することで型変換演算子(キャスト演算子、CType)を用いた型変換をサポート出来るようになります。
+

          
+
***暗黙的な型変換(拡大変換)演算子のオーバーロード
+
C#ではimplicit operator、VBではWidening Operator CTypeを用いることで暗黙の型変換演算子をオーバーロード出来ます。 この演算子は、拡大変換を定義する場合にオーバーロードします。 変換先の型は必ずしも基本型である必要は無く、変換が定義できるならどのような型への変換も実装出来ます。 また、変換先の型を複数定義することも出来ます。
+

          
+
次の例は、Complex型を暗黙的にDouble型およびString型へと変換できるよう演算子をオーバーロードする例です。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+

          
+
struct Complex
+
{
+
  public double Real; // 実部
+
  public double Imaginary; // 虚部
+

          
+
  public Complex(double real, double imaginary)
+
    : this()
+
  {
+
    this.Real = real;
+
    this.Imaginary = imaginary;
+
  }
+

          
+
  public override string ToString()
+
  {
+
    return string.Format("({0:F4}, {1:F4})", Real, Imaginary);
+
  }
+

          
+
  // doubleへの型変換演算子
+
  public static implicit operator double(Complex c)
+
  {
+
    return Math.Sqrt(c.Real * c.Real + c.Imaginary * c.Imaginary);
+
  }
+

          
+
  // stringへの型変換演算子
+
  public static implicit operator string(Complex c)
+
  {
+
    return c.ToString();
+
  }
+
}
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    Complex c1 = new Complex(-1.414, 1.414);
+
    Complex c2 = new Complex( 3.000, 4.000);
+

          
+
    double d1 = c1;
+
    double d2 = c2;
+

          
+
    Console.WriteLine("{0} => {1}", c1, d1);
+
    Console.WriteLine("{0} => {1}", c2, d2);
+

          
+
    string s1 = c1;
+
    string s2 = c2;
+

          
+
    Console.WriteLine("{0} => {1}", c1, s1);
+
    Console.WriteLine("{0} => {1}", c2, s2);
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+

          
+
Structure Complex
+
  Public Real As Double ' 実部
+
  Public Imaginary As Double ' 虚部
+

          
+
  Public Sub New(ByVal real As Double, ByVal imaginary As Double)
+
    MyClass.Real = real
+
    MyClass.Imaginary = imaginary
+
  End Sub
+

          
+
  Public Overrides Function ToString() As String
+
    Return String.Format("({0:F4}, {1:F4})", Real, Imaginary)
+
  End Function
+

          
+
  ' Doubleへの型変換演算子
+
  Public Shared Widening Operator CType(ByVal c As Complex) As Double
+
    Return Math.Sqrt(c.Real * c.Real + c.Imaginary * c.Imaginary)
+
  End Operator
+

          
+
  ' Stringへの型変換演算子
+
  Public Shared Widening Operator CType(ByVal c As Complex) As String
+
    Return c.ToString()
+
  End Operator
+
End Structure
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim c1 As New Complex(-1.414, 1.414)
+
    Dim c2 As New Complex( 3.000, 4.000)
+

          
+
    Dim d1 As Double = c1
+
    Dim d2 As Double = c2
+

          
+
    Console.WriteLine("{0} => {1}", c1, d1)
+
    Console.WriteLine("{0} => {1}", c2, d2)
+

          
+
    Dim s1 As String = c1
+
    Dim s2 As String = c2
+

          
+
    Console.WriteLine("{0} => {1}", c1, s1)
+
    Console.WriteLine("{0} => {1}", c2, s2)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
(-1.4140, 1.4140) => 1.99969797719556
+
(3.0000, 4.0000) => 5
+
(-1.4140, 1.4140) => (-1.4140, 1.4140)
+
(3.0000, 4.0000) => (3.0000, 4.0000)
+
}}
+

          
+
型変換演算子となるメソッドはpublic static/Public Sharedでなければなりません。 また、暗黙の型変換演算子のオーバーロードする際にはいくつかの注意が必要です。
+

          
+
暗黙の型変換演算子がオーバーロードされている場合、異なる型の変数への意図しない代入でも変換が行われてしまうことになります。 上記の例では、Complex型から暗黙的にString型へ変換することが出来るようになっていますが、これは他の多くの基本型とは異なる動作であるため、混乱を招く可能性があります。 このような場合の他、変換によりデータの欠損や桁落ち、オーバーフローが発生する場合は、代わりに明示的な型変換演算子を用いるべきです。 言い換えると、暗黙の変換が行われても予期しない結果となることもなく、変換により例外が発生しないような場合には、暗黙の型変換演算子をオーバーロードしても問題にはならないと言えます。
+

          
+
***明示的な型変換(縮小変換)演算子のオーバーロード
+
C#ではexplicit operator、VBではNarrowing Operator CTypeを用いることで明示的な型変換演算子をオーバーロード出来ます。 この演算子は、縮小変換を定義する場合にオーバーロードします。 暗黙的な型変換演算子と同様、変換先の型は必ずしも基本型である必要は無く、変換が定義できるならどのような型への変換も実装出来ます。 また、変換先の型を複数定義することも出来ます。
+

          
+
次の例は、Complex型を明示的にInteger型およびPointF型へと変換できるよう演算子をオーバーロードする例です。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Drawing;
 

        

        
~
struct Complex
        }
+
{
+
  public double Real; // 実部
+
  public double Imaginary; // 虚部
+

          
+
  public Complex(double real, double imaginary)
+
    : this()
+
  {
+
    this.Real = real;
+
    this.Imaginary = imaginary;
+
  }
+

          
+
  public override string ToString()
+
  {
+
    return string.Format("({0:F4}, {1:F4})", Real, Imaginary);
+
  }
+

          
+
  public static explicit operator int(Complex c)
+
  {
+
    // 実部・虚部の値が非数もしくは無限大の場合は、OverflowExceptionをスローする
+
    if (double.IsNaN(c.Real) || double.IsNaN(c.Imaginary) ||
+
        double.IsInfinity(c.Real) || double.IsInfinity(c.Imaginary))
+
      throw new OverflowException("NaN or Infinity");
+

          
+
    return Convert.ToInt32(Math.Sqrt(c.Real * c.Real + c.Imaginary * c.Imaginary));
+
  }
+

          
+
  public static explicit operator PointF(Complex c)
+
  {
+
    return new PointF(Convert.ToSingle(c.Real), Convert.ToSingle(c.Imaginary));
+
  }
+
}
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    Complex c1 = new Complex(-1.414, 1.414);
+
    Complex c2 = new Complex( 3.000, 4.000);
+

          
+
    int i1 = (int)c1;
+
    int i2 = (int)c2;
+

          
+
    Console.WriteLine("{0} => {1}", c1, i1);
+
    Console.WriteLine("{0} => {1}", c2, i2);
+

          
+
    PointF p1 = (PointF)c1;
+
    PointF p2 = (PointF)c2;
+

          
+
    Console.WriteLine("{0} => {1}", c1, p1);
+
    Console.WriteLine("{0} => {1}", c2, p2);
+

          
+
    Complex c3 = new Complex(double.NaN, double.NegativeInfinity);
+

          
+
    Console.WriteLine("{0} => {1}", c3, (PointF)c3);
+
    Console.WriteLine("{0} => {1}", c3, (int)c3);
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Drawing
+

          
+
Structure Complex
+
  Public Real As Double ' 実部
+
  Public Imaginary As Double ' 虚部
+

          
+
  Public Sub New(ByVal real As Double, ByVal imaginary As Double)
+
    MyClass.Real = real
+
    MyClass.Imaginary = imaginary
+
  End Sub
+

          
+
  Public Overrides Function ToString() As String
+
    Return String.Format("({0:F4}, {1:F4})", Real, Imaginary)
+
  End Function
+

          
+
  Public Shared Narrowing Operator CType(ByVal c As Complex) As Integer
+
    ' 実部・虚部の値が非数もしくは無限大の場合は、OverflowExceptionをスローする
+
    If Double.IsNaN(c.Real) OrElse Double.IsNaN(c.Imaginary) OrElse _
+
       Double.IsInfinity(c.Real) OrElse Double.IsInfinity(c.Imaginary) Then
+
      Throw New OverflowException("NaN or Infinity")
+
    Else
+
      Return Convert.ToInt32(Math.Sqrt(c.Real * c.Real + c.Imaginary * c.Imaginary))
+
    End If
+
  End Operator
+

          
+
  Public Shared Narrowing Operator CType(ByVal c As Complex) As PointF
+
    Return New PointF(Convert.ToSingle(c.Real), Convert.ToSingle(c.Imaginary))
+
  End Operator
+
End Structure
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim c1 As New Complex(-1.414, 1.414)
+
    Dim c2 As New Complex( 3.000, 4.000)
+

          
+
    Dim i1 As Integer = CInt(c1)
+
    Dim i2 As Integer = CType(c2, Integer)
+

          
+
    Console.WriteLine("{0} => {1}", c1, i1)
+
    Console.WriteLine("{0} => {1}", c2, i2)
+

          
+
    Dim p1 As PointF = CType(c1, PointF)
+
    Dim p2 As PointF = CType(c2, PointF)
+

          
+
    Console.WriteLine("{0} => {1}", c1, p1)
+
    Console.WriteLine("{0} => {1}", c2, p2)
+

          
+
    Dim c3 As New Complex(Double.NaN, Double.NegativeInfinity)
+

          
+
    Console.WriteLine("{0} => {1}", c3, CType(c3, PointF))
+
    Console.WriteLine("{0} => {1}", c3, CType(c3, Integer))
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
(-1.4140, 1.4140) => 2
+
(3.0000, 4.0000) => 5
+
(-1.4140, 1.4140) => {X=-1.414, Y=1.414}
+
(3.0000, 4.0000) => {X=3, Y=4}
+
(NaN (非数値), -∞) => {X=NaN (非数値), Y=-∞}
+

          
+
ハンドルされていない例外: System.OverflowException: NaN or Infinity
+
   場所 Complex.op_Explicit(Complex c)
+
   場所 Sample.Main()
+
}}
+

          
+
暗黙的な型変換演算子と同様、明示的な型変換演算子となるメソッドはpublic static/Public Sharedでなければなりません。 また、暗黙的な型変換演算子とは異なり、変換に際してOverflowException、InvalidCastException、FormatExceptionなどの例外をスローすることが出来ます。 上記の例では、非数もしくは無限大の値を持つ場合、Integer型への変換時にOverflowExceptionをスローするようにしていますが、値が変換できない形式ならFormatException、定義できない変換であればInvalidCastExceptionをスローするように出来ます。
+

          
+
***相互変換が可能な型でのオーバーロード
+
二つの型で型変換演算子をオーバーロードすることで、型を相互に変換できるようにすることが出来ます。 以下の例では、直交形式と極形式の二つの形式で複素数を表現する型を用意し、相互に変換できるよう演算子をオーバーロードしています。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+

          
+
struct CartesianComplex
+
{
+
  public double Real; // 実部
+
  public double Imaginary; // 虚部
+

          
+
  public CartesianComplex(double real, double imaginary)
+
    : this()
+
  {
+
    this.Real = real;
+
    this.Imaginary = imaginary;
+
  }
+

          
+
  public override string ToString()
+
  {
+
    return string.Format("({0:F4}, {1:F4})", Real, Imaginary);
+
  }
+

          
+
  // PolarComplexへの型変換
+
  public static explicit operator PolarComplex(CartesianComplex c)
+
  {
+
    return new PolarComplex(Math.Sqrt(c.Real * c.Real + c.Imaginary * c.Imaginary),
+
                            Math.Atan2(c.Imaginary, c.Real));
+
  }
+
}
+

          
+
struct PolarComplex
+
{
+
  public double Magnitude; // 絶対値
+
  public double Phase; // 偏角
+

          
+
  public PolarComplex(double magnitude, double phase)
+
    : this()
+
  {
+
    this.Magnitude = magnitude;
+
    this.Phase = phase;
+
  }
+

          
+
  public override string ToString()
+
  {
+
    return string.Format("{0:F4}∠{1:F4}π", Magnitude, Phase / Math.PI);
+
  }
+

          
+
  // CartesianComplexへの型変換
+
  public static explicit operator CartesianComplex(PolarComplex c)
+
  {
+
    return new CartesianComplex(c.Magnitude * Math.Cos(c.Phase),
+
                                c.Magnitude * Math.Sin(c.Phase));
+
  }
+
}
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    CartesianComplex c1 = new CartesianComplex(-1.414, 1.414);
+
    CartesianComplex c2 = new CartesianComplex( 3.000, 4.000);
+

          
+
    PolarComplex p1 = (PolarComplex)c1;
+
    PolarComplex p2 = (PolarComplex)c2;
+

          
+
    Console.WriteLine("{0} => {1}", c1, p1);
+
    Console.WriteLine("{0} => {1}", c2, p2);
+

          
+
    c1 = (CartesianComplex)p1;
+
    c2 = (CartesianComplex)p2;
+

          
+
    Console.WriteLine("{0} => {1}", p1, c1);
+
    Console.WriteLine("{0} => {1}", p2, c2);
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+

          
+
Structure CartesianComplex
+
  Public Real As Double ' 実部
+
  Public Imaginary As Double ' 虚部
+

          
+
  Public Sub New(ByVal real As Double, ByVal imaginary As Double)
+
    MyClass.Real = real
+
    MyClass.Imaginary = imaginary
+
  End Sub
+

          
+
  Public Overrides Function ToString() As String
+
    Return String.Format("({0:F4}, {1:F4})", Real, Imaginary)
+
  End Function
+

          
+
  ' PolarComplexへの型変換
+
  Public Shared Narrowing Operator CType(ByVal c As CartesianComplex) As PolarComplex
+
    Return New PolarComplex(Math.Sqrt(c.Real * c.Real + c.Imaginary * c.Imaginary), _
+
                            Math.Atan2(c.Imaginary, c.Real))
+
  End Operator
+
End Structure
+

          
+
Structure PolarComplex
+
  Public Magnitude As Double ' 絶対値
+
  Public Phase As Double ' 偏角
+

          
+
  Public Sub New(ByVal magnitude As Double, ByVal phase As Double)
+
    MyClass.Magnitude = magnitude
+
    MyClass.Phase = phase
+
  End Sub
+

          
+
  Public Overrides Function ToString() As String
+
    Return String.Format("{0:F4}∠{1:F4}π", Magnitude, Phase / Math.PI)
+
  End Function
+

          
+
  ' CartesianComplexへの型変換
+
  Public Shared Narrowing Operator CType(ByVal c As PolarComplex) As CartesianComplex
+
    Return New CartesianComplex(c.Magnitude * Math.Cos(c.Phase), _
+
                                c.Magnitude * Math.Sin(c.Phase))
+
  End Operator
+
End Structure
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim c1 As New CartesianComplex(-1.414, 1.414)
+
    Dim c2 As New CartesianComplex( 3.000, 4.000)
+

          
+
    Dim p1 As PolarComplex = CType(c1, PolarComplex)
+
    Dim p2 As PolarComplex = CType(c2, PolarComplex)
+

          
+
    Console.WriteLine("{0} => {1}", c1, p1)
+
    Console.WriteLine("{0} => {1}", c2, p2)
+

          
+
    c1 = CType(p1, CartesianComplex)
+
    c2 = CType(p2, CartesianComplex)
+

          
+
    Console.WriteLine("{0} => {1}", p1, c1)
+
    Console.WriteLine("{0} => {1}", p2, c2)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
(-1.4140, 1.4140) => 1.9997∠0.7500π
+
(3.0000, 4.0000) => 5.0000∠0.2952π
+
1.9997∠0.7500π => (-1.4140, 1.4140)
+
5.0000∠0.2952π => (3.0000, 4.0000)
+
}}
+

          
+
この例では、CartesianComplexからPolarComplexへの変換はCartesianComplexで、PolarComplexからCartesianComplexへの変換はPolarComplexで定義していますが、型変換演算子をオーバーロードする場合は必ずしも変換元の型に実装しなければならないというわけではなく、変換前・変換先の型ならどちらでも定義することが出来ます。 次の例では、先の例での型変換演算子の両方をPolarComplexでオーバーロードしています。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+

          
+
struct CartesianComplex
+
{
+
  public double Real; // 実部
+
  public double Imaginary; // 虚部
+

          
+
  public CartesianComplex(double real, double imaginary)
+
    : this()
+
  {
+
    this.Real = real;
+
    this.Imaginary = imaginary;
+
  }
+

          
+
  public override string ToString()
+
  {
+
    return string.Format("({0:F4}, {1:F4})", Real, Imaginary);
+
  }
+
}
+

          
+
struct PolarComplex
+
{
+
  public double Magnitude; // 絶対値
+
  public double Phase; // 偏角
+

          
+
  public PolarComplex(double magnitude, double phase)
+
    : this()
+
  {
+
    this.Magnitude = magnitude;
+
    this.Phase = phase;
+
  }
+

          
+
  public override string ToString()
+
  {
+
    return string.Format("{0:F4}∠{1:F4}π", Magnitude, Phase / Math.PI);
+
  }
+

          
+
  // CartesianComplexからPolarComplexへの型変換
+
  public static explicit operator PolarComplex(CartesianComplex c)
+
  {
+
    return new PolarComplex(Math.Sqrt(c.Real * c.Real + c.Imaginary * c.Imaginary),
+
                            Math.Atan2(c.Imaginary, c.Real));
+
  }
+

          
+
  // PolarComplexからCartesianComplexへの型変換
+
  public static explicit operator CartesianComplex(PolarComplex c)
+
  {
+
    return new CartesianComplex(c.Magnitude * Math.Cos(c.Phase),
+
                                c.Magnitude * Math.Sin(c.Phase));
+
  }
+
}
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    CartesianComplex c1 = new CartesianComplex(-1.414, 1.414);
+
    CartesianComplex c2 = new CartesianComplex( 3.000, 4.000);
+

          
+
    PolarComplex p1 = (PolarComplex)c1;
+
    PolarComplex p2 = (PolarComplex)c2;
+

          
+
    Console.WriteLine("{0} => {1}", c1, p1);
+
    Console.WriteLine("{0} => {1}", c2, p2);
+

          
+
    c1 = (CartesianComplex)p1;
+
    c2 = (CartesianComplex)p2;
+

          
+
    Console.WriteLine("{0} => {1}", p1, c1);
+
    Console.WriteLine("{0} => {1}", p2, c2);
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+

          
+
Structure CartesianComplex
+
  Public Real As Double ' 実部
+
  Public Imaginary As Double ' 虚部
+

          
+
  Public Sub New(ByVal real As Double, ByVal imaginary As Double)
+
    MyClass.Real = real
+
    MyClass.Imaginary = imaginary
+
  End Sub
+

          
+
  Public Overrides Function ToString() As String
+
    Return String.Format("({0:F4}, {1:F4})", Real, Imaginary)
+
  End Function
+
End Structure
+

          
+
Structure PolarComplex
+
  Public Magnitude As Double ' 絶対値
+
  Public Phase As Double ' 偏角
+

          
+
  Public Sub New(ByVal magnitude As Double, ByVal phase As Double)
+
    MyClass.Magnitude = magnitude
+
    MyClass.Phase = phase
+
  End Sub
+

          
+
  Public Overrides Function ToString() As String
+
    Return String.Format("{0:F4}∠{1:F4}π", Magnitude, Phase / Math.PI)
+
  End Function
+

          
+
  ' CartesianComplexからPolarComplexへの型変換
+
  Public Shared Narrowing Operator CType(ByVal c As CartesianComplex) As PolarComplex
+
    Return New PolarComplex(Math.Sqrt(c.Real * c.Real + c.Imaginary * c.Imaginary), _
+
                            Math.Atan2(c.Imaginary, c.Real))
+
  End Operator
+

          
+
  ' PolarComplexからCartesianComplexへの型変換
+
  Public Shared Narrowing Operator CType(ByVal c As PolarComplex) As CartesianComplex
+
    Return New CartesianComplex(c.Magnitude * Math.Cos(c.Phase), _
+
                                c.Magnitude * Math.Sin(c.Phase))
+
  End Operator
+
End Structure
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim c1 As New CartesianComplex(-1.414, 1.414)
+
    Dim c2 As New CartesianComplex( 3.000, 4.000)
+

          
+
    Dim p1 As PolarComplex = CType(c1, PolarComplex)
+
    Dim p2 As PolarComplex = CType(c2, PolarComplex)
+

          
+
    Console.WriteLine("{0} => {1}", c1, p1)
+
    Console.WriteLine("{0} => {1}", c2, p2)
+

          
+
    c1 = CType(p1, CartesianComplex)
+
    c2 = CType(p2, CartesianComplex)
+

          
+
    Console.WriteLine("{0} => {1}", p1, c1)
+
    Console.WriteLine("{0} => {1}", p2, c2)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
(-1.4140, 1.4140) => 1.9997∠0.7500π
+
(3.0000, 4.0000) => 5.0000∠0.2952π
+
1.9997∠0.7500π => (-1.4140, 1.4140)
+
5.0000∠0.2952π => (3.0000, 4.0000)
+
}}
+

          
+
当然ながら、型変換演算子からは他の型の非パブリックなメンバにはアクセス出来ないので、この例の様な方法が採れる場合は多くはありません。
+

          
+
**その他
+
***Converter<TInput, TOutput>
+
&msdn(netfx,id,kt456a2y){Converterジェネリックデリゲート};は任意の型変換を行うメソッドを表すデリゲートです。 このデリゲートは、&msdn(netfx,method,System.Array.ConvertAll){Array.ConvertAll};や&msdn(netfx,id,73fe8cwf){List.ConvertAll};などのメソッドで、特定の型から別の型に変換する場合に使われます。 型パラメータTInputとTOutputで変換前と変換後の型を任意に指定することが出来ます。 このデリゲートと変換を行うメソッドを組み合わせて使うことで、型変換演算子が定義されていない・Convertクラスで変換できない場合や異なる変換ルールを使用したい場合に、独自に変換処理を定義して型の変換を行えるようになります。
+

          
+
次の例では、Converterデリゲートを使って複素数Complex型の配列をPoint型の配列に変換しています。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Drawing;
+

          
+
struct Complex
+
{
+
  public double Real; // 実部
+
  public double Imaginary; // 虚部
+

          
+
  public Complex(double real, double imaginary)
+
    : this()
+
  {
+
    this.Real = real;
+
    this.Imaginary = imaginary;
+
  }
+

          
+
  public override string ToString()
+
  {
+
    return string.Format("({0:F4}, {1:F4})", Real, Imaginary);
+
  }
+
}
+

          
+
class Sample
+
{
+
  // ComplexをPointに変換するメソッド
+
  static Point ConvertToPoint(Complex c)
+
  {
+
    return new Point(Convert.ToInt32(c.Real), Convert.ToInt32(c.Imaginary));
+
  }
+

          
+
  static void Main()
+
  {
+
    Complex[] cxs = new[] {
+
      new Complex(-1.414, 1.414),
+
      new Complex( 3.000, 4.000),
+
      new Complex( 0.000, 0.000),
+
    };
+

          
+
    foreach (Complex e in cxs)
+
    {
+
      Console.WriteLine(e);
 
    }
    }
+

          
+
    Point[] pts = Array.ConvertAll(cxs, ConvertToPoint);
+

          
+
    foreach (Point e in pts)
+
    {
+
      Console.WriteLine(e);
+
    }
+
  }
 
}
}
 
}}
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Drawing
+

          
+
Structure Complex
+
  Public Real As Double ' 実部
+
  Public Imaginary As Double ' 虚部
+

          
+
  Public Sub New(ByVal real As Double, ByVal imaginary As Double)
+
    MyClass.Real = real
+
    MyClass.Imaginary = imaginary
+
  End Sub
+

          
+
  Public Overrides Function ToString() As String
+
    Return String.Format("({0:F4}, {1:F4})", Real, Imaginary)
+
  End Function
+
End Structure
+

          
+
Class Sample
+
  ' ComplexをPointに変換するメソッド
+
  Shared Function ConvertToPoint(ByVal c As Complex) As Point
+
    Return New Point(Convert.ToInt32(c.Real), Convert.ToInt32(c.Imaginary))
+
  End Function
+

          
+
  Shared Sub Main()
+
    Dim cxs() As Complex = New Complex() { _
+
      New Complex(-1.414, 1.414), _
+
      New Complex( 3.000, 4.000), _
+
      New Complex( 0.000, 0.000) _
+
    }
+

          
+
    For Each c As Complex In cxs
+
      Console.WriteLine(c)
+
    Next
+

          
+
    Dim pts() As Point = Array.ConvertAll(cxs, AddressOf ConvertToPoint)
+

          
+
    For Each p As Point In pts
+
      Console.WriteLine(p)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
 

        

        
~
#prompt{{
#prompt(実行結果){{
~
(-1.4140, 1.4140)
One of TypeA said, "I'm a instance of TypeB."
~
(3.0000, 4.0000)
One of TypeB said, "I'm a instance of TypeA."
~
(0.0000, 0.0000)
Press any key to continue
+
{X=-1,Y=1}
+
{X=3,Y=4}
+
{X=0,Y=0}
 
}}
}}
 

        

        

programming/vb.net/basics/06_math/index.wiki.txt

current previous
37,7 37,7
 
    floor = Math.Floor(value)
    floor = Math.Floor(value)
 
    round = Math.Round(value)
    round = Math.Round(value)
 

        

        
~
    Console.WriteLine("Value: {0,5:F2}, {1,5:F2} {2,5:F2} {3,5:F2}", value, ceiling, floor, round)
    Console.WriteLine("Value: {0:F2}, {1:F2} {2:F2} {3:F2}", value, ceiling, floor, round)
 

        

        
 
Next
Next
 
}}
}}
48,75 48,62
 
Value: -1.50, -1.00 -2.00 -2.00
Value: -1.50, -1.00 -2.00 -2.00
 
Value: -1.25, -1.00 -2.00 -1.00
Value: -1.25, -1.00 -2.00 -1.00
 
Value: -1.00, -1.00 -1.00 -1.00
Value: -1.00, -1.00 -1.00 -1.00
~
Value: -0.75,  0.00 -1.00 -1.00
Value: -0.75, 0.00 -1.00 -1.00
~
Value: -0.50,  0.00 -1.00  0.00
Value: -0.50, 0.00 -1.00 0.00
~
Value: -0.25,  0.00 -1.00  0.00
Value: -0.25, 0.00 -1.00 0.00
~
Value:  0.00,  0.00  0.00  0.00
Value: 0.00, 0.00 0.00 0.00
~
Value:  0.25,  1.00  0.00  0.00
Value: 0.25, 1.00 0.00 0.00
~
Value:  0.50,  1.00  0.00  0.00
Value: 0.50, 1.00 0.00 0.00
~
Value:  0.75,  1.00  0.00  1.00
Value: 0.75, 1.00 0.00 1.00
~
Value:  1.00,  1.00  1.00  1.00
Value: 1.00, 1.00 1.00 1.00
~
Value:  1.25,  2.00  1.00  1.00
Value: 1.25, 2.00 1.00 1.00
~
Value:  1.50,  2.00  1.00  2.00
Value: 1.50, 2.00 1.00 2.00
~
Value:  1.75,  2.00  1.00  2.00
Value: 1.75, 2.00 1.00 2.00
~
Value:  2.00,  2.00  2.00  2.00
Value: 2.00, 2.00 2.00 2.00
~
}}
}}
~

          

          
~
Ceiling()メソッドは「指定された数以上の数のうち、最小の整数」、Floor()メソッドは「指定された数以下の数のうち、最大の整数」を返します。
これらのメソッドにおいて、
-
-Ceiling()は「指定された数以上の数のうち、最小の整数」
-
-Floor()は「指定された数以下の数のうち、最大の整数」
-
-Round()は「指定した値に最も近い整数」
 

        

        
~
Round()メソッドは、引数に丸めの際のオプションを指定することが出来ます。 オプションを指定しなかった場合もしくはMidpointRounding.ToEvenを指定した場合は際近接偶数への丸め、MidpointRounding.AwayFromZeroを指定した場合は四捨五入による丸めとなります。 また、丸めを行う桁数を指定することも出来ます。
を返します。 ただ、Round()は単純に四捨五入ではないので注意が必要です。
 

        

        
 
#code(vb){{
#code(vb){{
 
Dim value As Double
Dim value As Double
+
Dim r1, r2, r3 As Double
 

        

        
~
For value = -2.0 To 2.0 Step +0.125
For value = 0.0 To 2.0 Step +0.1
 

        

        
~
    r1 = Math.Round(value)
    Console.WriteLine("Value: {0:F2}, {1:F2}", value, Math.Round(value))
+
    r2 = Math.Round(value, MidpointRounding.AwayFromZero)
+
    r3 = Math.Round(value, 1, MidpointRounding.AwayFromZero)
+

          
+
    Console.WriteLine("Value: {0,6:F3}, {1,6:F3} {2,6:F3} {3,6:F3}", value, r1, r2, r3)
 

        

        
 
Next
Next
 
}}
}}
 

        

        
 
#prompt(実行結果){{
#prompt(実行結果){{
~
Value: -2.000, -2.000 -2.000 -2.000
Value: 0.00, 0.00
~
Value: -1.875, -2.000 -2.000 -1.900
Value: 0.10, 0.00
~
Value: -1.750, -2.000 -2.000 -1.800
Value: 0.20, 0.00
~
Value: -1.625, -2.000 -2.000 -1.600
Value: 0.30, 0.00
~
Value: -1.500, -2.000 -2.000 -1.500
Value: 0.40, 0.00
~
Value: -1.375, -1.000 -1.000 -1.400
Value: 0.50, 0.00
~
Value: -1.250, -1.000 -1.000 -1.300
Value: 0.60, 1.00
~
Value: -1.125, -1.000 -1.000 -1.100
Value: 0.70, 1.00
~
Value: -1.000, -1.000 -1.000 -1.000
Value: 0.80, 1.00
~
Value: -0.875, -1.000 -1.000 -0.900
Value: 0.90, 1.00
~
Value: -0.750, -1.000 -1.000 -0.800
Value: 1.00, 1.00
~
Value: -0.625, -1.000 -1.000 -0.600
Value: 1.10, 1.00
~
Value: -0.500,  0.000 -1.000 -0.500
Value: 1.20, 1.00
~
Value: -0.375,  0.000  0.000 -0.400
Value: 1.30, 1.00
~
Value: -0.250,  0.000  0.000 -0.300
Value: 1.40, 1.00
~
Value: -0.125,  0.000  0.000 -0.100
Value: 1.50, 2.00
~
Value:  0.000,  0.000  0.000  0.000
Value: 1.60, 2.00
~
Value:  0.125,  0.000  0.000  0.100
Value: 1.70, 2.00
~
Value:  0.250,  0.000  0.000  0.300
Value: 1.80, 2.00
~
Value:  0.375,  0.000  0.000  0.400
Value: 1.90, 2.00
+
Value:  0.500,  0.000  1.000  0.500
+
Value:  0.625,  1.000  1.000  0.600
+
Value:  0.750,  1.000  1.000  0.800
+
Value:  0.875,  1.000  1.000  0.900
+
Value:  1.000,  1.000  1.000  1.000
+
Value:  1.125,  1.000  1.000  1.100
+
Value:  1.250,  1.000  1.000  1.300
+
Value:  1.375,  1.000  1.000  1.400
+
Value:  1.500,  2.000  2.000  1.500
+
Value:  1.625,  2.000  2.000  1.600
+
Value:  1.750,  2.000  2.000  1.800
+
Value:  1.875,  2.000  2.000  1.900
+
Value:  2.000,  2.000  2.000  2.000
 
}}
}}
 

        

        
-
Round()メソッドの挙動について、MSDNライブラリには「指定された値が 2 つの整数(一方の整数が偶数でもう一方が奇数)の中間にある場合は偶数が返されます」とあります。
-

          
 
*累乗・平方根
*累乗・平方根
 
累乗を計算するにはPow()メソッドを使用します。 また、平方根を求めるにはSqrt()メソッドを使用します。 ただ、VB.NETには^演算子が存在するので、これらのメソッドを使用しなくても累乗・平方根などを算出することができます。
累乗を計算するにはPow()メソッドを使用します。 また、平方根を求めるにはSqrt()メソッドを使用します。 ただ、VB.NETには^演算子が存在するので、これらのメソッドを使用しなくても累乗・平方根などを算出することができます。
 
#code(vb){{
#code(vb){{