2010-09-26T16:25:07の更新内容

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

current previous
1,91 1,53
 
${smdncms:title,構造体の属性と共用体(StructLayoutAttribute, FieldOffsetAttribute)}
${smdncms:title,構造体の属性と共用体(StructLayoutAttribute, FieldOffsetAttribute)}
+
${smdncms:keywords,共用体,StructLayout,FieldOffset,union}
 
${smdncms:meta,toc-amazonlivelink-keyword,books-jp,.net framework}
${smdncms:meta,toc-amazonlivelink-keyword,books-jp,.net framework}
~
.NET Framework の共通言語仕様(CLS)には共用体(C/C++のunion)は存在しません。 また、C#にもVB.NETにも共用体は存在しません。 共用体自体はそれほど使う機会が多いというわけではないですし、また、なければならないというものでもありません。 しかし、ごく稀にあると便利かなと思うことがあります。 そういうときに、.NET Frameworkの&msdn(netfx,type,System.Runtime.InteropServices.StructLayoutAttribute){StructLayout};属性と&msdn(netfx,type,System.Runtime.InteropServices.FieldOffsetAttribute){FieldOffset};属性を用いることでC#やVB.NETの構造体でも共用体の機能を再現することができます。
.NET Framework の共通言語仕様(CLS)には共用体は存在しません。 また、C#にもVB.NETにも共用体は存在しません。 共用体自体はそれほど使う機会が多いというわけではないですし、また、なければならないというものでもありません。 しかし、ごく稀にあると便利かなと思うことがあります。 そういうときに、.NET FrameworkのStructLayout属性とFieldOffset属性を用いることでC#やVB.NETの構造体でも共用体の機能を再現することができます。
+

          
+
-関連するページ
+
--[[programming/netfx2/overview/attribute]]
+
--[[programming/netfx2/overview/classlibrary]]
+

          
 
#googleadunit
#googleadunit
 

        

        
 
*StructLayout属性とFieldOffset属性
*StructLayout属性とFieldOffset属性
~
それではまず&msdn(netfx,type,System.Runtime.InteropServices.StructLayoutAttribute){StructLayout};属性について見てみることにします。 この属性は構造体(クラスでも可)に対して適用し、この属性を適用することで構造体の各メンバ変数(フィールド)のメモリ上での配置方法を指定することができます。 配置方法は、&msdn(netfx,type,System.Runtime.InteropServices.LayoutKind){LayoutKind};で指定することができ、次のいずれかを指定することが出来ます。
それではまずStructLayout属性について見てみることにします。 この属性は構造体(クラスも可)に対して適用し、この属性を適用することで構造体の各メンバ変数のメモリ上での配置方法を指定することができます。 具体的には、LayoutKind.Autoを指定するとコンパイラが最も適した方法で配置し、LayoutKind.Sequentialを指定するとメモリ内に連続して順番に配置され、 LayoutKind.Explicitを指定するとプログラム側で明示的に位置を指定しなければなりません。
+
:LayoutKind.Auto|ランタイムが自動的に、最適な方法でメンバを配置 (StructLayout属性を指定しない場合と同じ)
+
:LayoutKind.Sequential|ランタイムによる自動的な並べ替えを行わず、記述した順序のままメンバを配置
+
:LayoutKind.Explicit|プログラム側で明示的に位置を指定してメンバを配置
 

        

        
~
LayoutKind.Explicitを指定した場合は、全てのメンバ変数に対して明示的に位置を指定しなければなりません。 メンバ変数の位置を指定するために使用する属性が&msdn(netfx,type,System.Runtime.InteropServices.FieldOffsetAttribute){FieldOffset};属性です。 この属性では構造体の先頭からのオフセット値をバイト単位で指定します。
また、ここでLayoutKind.Explicitを指定すると、全てのメンバ変数に対して明示的に位置を指定しなければなりません。 そこで、位置を指定するために使用する属性がFieldOffset属性です。 この属性では構造体の先頭から各メンバ変数の先頭までのオフセット値をバイト単位で指定します。
 

        

        
~
それでは、早速これらの属性を適用した構造体を作成してみようと思います。 このサンプルではshortではなく System.UInt16を用いていますが、16Bitの符号無し整数型を用いていると言うことを視覚的に表すためであって、それ以上の意味はありません。
それでは、早速これらの属性を適用した構造体を作成してみようと思います。 このサンプルではshortではなく System.UInt16を用いていますが、16Bitの符号無し整数型を用いていると言うことを視覚的に表すためであって、それ以外に深い意味はありません。
+
#tabpage(C#)
 
#code(cs){{
#code(cs){{
 
using System;
using System;
 
using System.Runtime.InteropServices;
using System.Runtime.InteropServices;
 

        

        
~
// StructLayout属性及びFieldOffset属性を適用した構造体
namespace StructAndUnion
+
[StructLayout(LayoutKind.Explicit)]
+
struct SampleStruct
 
{
{
~
  [FieldOffset(0)] public System.UInt16 Value1;
    // StructLayout属性及びFieldOffset属性を適用した構造体
~
  [FieldOffset(2)] public System.UInt16 Value2;
    [StructLayout(LayoutKind.Explicit)]
~
  [FieldOffset(4)] public System.UInt16 Value3;
    struct SampleStruct
~
  [FieldOffset(6)] public System.UInt16 Value4;
    {
~
}
        [FieldOffset(0)] public System.UInt16 Value1;
-
        [FieldOffset(2)] public System.UInt16 Value2;
-
        [FieldOffset(4)] public System.UInt16 Value3;
-
        [FieldOffset(6)] public System.UInt16 Value4;
-
    }
 

        

        
~
class SampleClass
    // アプリケーションのエントリーポイントを提供するクラス
~
{
    class SampleClass
~
  static void Main()
    {
~
  {
        [STAThread]
~
    SampleStruct s = new SampleStruct();
        static void Main(string[] args)
~

          
        {
~
    // 各フィールドに値を指定
            SampleStruct s = new SampleStruct();
~
    s.Value1 = 0x1122;

          
~
    s.Value2 = 0x3344;
            // 各フィールドに値を指定
~
    s.Value3 = 0x5566;
            s.Value1 = 0x1122;
~
    s.Value4 = 0x7788;
            s.Value2 = 0x3344;
~

          
            s.Value3 = 0x5566;
~
    // 各フィールドの値を表示
            s.Value4 = 0x7788;
~
    Console.WriteLine("SampleStruct.Value1 : 0x" + s.Value1.ToString("X4"));

          
~
    Console.WriteLine("SampleStruct.Value2 : 0x" + s.Value2.ToString("X4"));
            // 各フィールドの値を表示
~
    Console.WriteLine("SampleStruct.Value3 : 0x" + s.Value3.ToString("X4"));
            Console.WriteLine( "SampleStruct.Value1 : 0x" + s.Value1.ToString("X4") );
~
    Console.WriteLine("SampleStruct.Value4 : 0x" + s.Value4.ToString("X4"));
            Console.WriteLine( "SampleStruct.Value2 : 0x" + s.Value2.ToString("X4") );
~
  }
            Console.WriteLine( "SampleStruct.Value3 : 0x" + s.Value3.ToString("X4") );
-
            Console.WriteLine( "SampleStruct.Value4 : 0x" + s.Value4.ToString("X4") );
-
        }
-
    }
 
}
}
 
}}
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Runtime.InteropServices
+

          
+
' StructLayout属性及びFieldOffset属性を適用した構造体
+
<StructLayout(LayoutKind.Explicit)> _
+
Structure SampleStruct
+
  <FieldOffset(0)> Public Value1 As System.UInt16
+
  <FieldOffset(2)> Public Value2 As System.UInt16
+
  <FieldOffset(4)> Public Value3 As System.UInt16
+
  <FieldOffset(6)> Public Value4 As System.UInt16
+
End Structure
+

          
+
Class SampleClass
+
  Shared Sub Main()
+
    Dim s As New SampleStruct()
+

          
+
    ' 各フィールドに値を指定
+
    s.Value1 = &h1122
+
    s.Value2 = &h3344
+
    s.Value3 = &h5566
+
    s.Value4 = &h7788
+

          
+
    ' 各フィールドの値を表示
+
    Console.WriteLine("SampleStruct.Value1 : 0x" + s.Value1.ToString("X4"))
+
    Console.WriteLine("SampleStruct.Value2 : 0x" + s.Value2.ToString("X4"))
+
    Console.WriteLine("SampleStruct.Value3 : 0x" + s.Value3.ToString("X4"))
+
    Console.WriteLine("SampleStruct.Value4 : 0x" + s.Value4.ToString("X4"))
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
 

        

        
 
#prompt(実行結果){{
#prompt(実行結果){{
 
SampleStruct.Value1 : 0x1122
SampleStruct.Value1 : 0x1122
95,298 57,248
 
Press any key to continue
Press any key to continue
 
}}
}}
 

        

        
+
この結果を見てわかるとおり、通常の構造体の場合と何ら変わりないように思われます。 しかし、メモリ上の配置は次の図のようになっているはずです。
 
#ref(0.png,メモリ上の配置)
#ref(0.png,メモリ上の配置)
 

        

        
~
LayoutKind.ExplicitではなくLayoutKind.Sequentialを指定した場合、&msdn(netfx,member,System.Runtime.InteropServices.StructLayoutAttribute.Pack){StructLayoutAttribute.Packフィールド};で構造体のアライメントを指定することも出来ますが、詳細はここでは省略します。
この結果を見てわかるとおり、通常の構造体の場合と何ら変わりないように思われます。 しかし、メモリ上の配置は図のようになっているはずです。 (ところで、.NET Frameworkってビッグエンディアンでしたっけ・・・実はハードウェアとかメモリ関連のことはいまいちなのでもしかしたら図は間違ってるかもしれません・・・間違ってたらご指摘下さい。)
 

        

        
 
*共用体を作る
*共用体を作る
~
このように、StructLayout属性で明示的にメンバ変数の配置方法を指定することができ、FieldOffsetでメンバ変数のオフセット値を指定することが出きるとなれば、共用体を作る方法はおのずと浮かんでくるはずです。 共用体では一つ以上のメンバ変数が、同じメモリ領域を共用します。 つまり、メンバ変数のオフセット値を全て同じにすれば、共用体と同じ構造の構造体を作ることができることになります。
このように、StructLayout属性で明示的に配置方法を指定することができ、FieldOffsetでメンバ変数のオフセット値を指定することが出きるとなれば、共用体を作る方法はおのずと浮かんでくるはずです。 つまり、共用体の仕組み・構造を思い浮かべて下さい。 共用体では一つ以上の同じまたは異なる型のメンバが、同じメモリ領域を共用します。 つまり、メンバ変数のオフセット値を全て同じにすれば、共用体と同じ構造の構造体を作ることができることになります。
 

        

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

        

        
~
// 構造体で再現した共用体
namespace StructAndUnion
+
[StructLayout(LayoutKind.Explicit)]
+
struct DoubleWord
 
{
{
~
  [FieldOffset(0)] public System.UInt32 Value;
    // 構造体で再現した共用体
-
    [StructLayout(LayoutKind.Explicit)]
-
    struct DoubleWord
-
    {
-
        [FieldOffset(0)] public System.UInt32 Value;
-
        
-
        [FieldOffset(0)] public System.UInt16 LowWord;
-
        [FieldOffset(2)] public System.UInt16 HighWord;
-
    }
 

        

        
~
  [FieldOffset(0)] public System.UInt16 LowWord;
    // アプリケーションのエントリーポイントを提供するクラス
~
  [FieldOffset(2)] public System.UInt16 HighWord;
    class SampleClass
-
    {
-
        [STAThread]
-
        static void Main(string[] args)
-
        {
-
            DoubleWord dw = new DoubleWord();
-

          
-
            // ダブルワード値を指定
-
            dw.Value = 0x11223344;
-

          
-
            // 下位ワードと上位ワードを表示
-
            Console.WriteLine(  "Low word: 0x" + dw.LowWord.ToString("X4") );
-
            Console.WriteLine( "High word: 0x" + dw.HighWord.ToString("X4") );
-
        }
-
    }
 
}
}
+

          
+
class SampleClass
+
{
+
  static void Main()
+
  {
+
    DoubleWord dw = new DoubleWord();
+

          
+
    // ダブルワード値を指定
+
    dw.Value = 0x11223344;
+

          
+
    // 下位ワードと上位ワードを表示
+
    Console.WriteLine(" Low word: 0x" + dw.LowWord.ToString("X4"));
+
    Console.WriteLine("High word: 0x" + dw.HighWord.ToString("X4"));
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Runtime.InteropServices
+

          
+
' 構造体で再現した共用体
+
<StructLayout(LayoutKind.Explicit)> _
+
Structure DoubleWord
+
  <FieldOffset(0)> Public Value As System.UInt32
+

          
+
  <FieldOffset(0)> Public LowWord As System.UInt16
+
  <FieldOffset(2)> Public HighWord As System.UInt16
+
End Structure
+

          
+
Class SampleClass
+
  Shared Sub Main()
+
    Dim dw As New DoubleWord()
+

          
+
    ' ダブルワード値を指定
+
    dw.Value = &h11223344
+

          
+
    ' 各フィールドの値を表示
+
    Console.WriteLine(" Low word: 0x" + dw.LowWord.ToString("X4"))
+
    Console.WriteLine("High word: 0x" + dw.HighWord.ToString("X4"))
+
  End Sub
+
End Class
 
}}
}}
+
#tabpage-end
 

        

        
 
#prompt(実行結果){{
#prompt(実行結果){{
~
 Low word: 0x3344
Low word : 0x3344
~
High word: 0x1122
High word : 0x1122
 
Press any key to continue
Press any key to continue
 
}}
}}
 

        

        
+
この結果から、この構造体が共用体と同様の機能を得ていることがわかります。 メモリ上の配置は次のようになっています。
 
#ref(1.png,メモリ上の配置)
#ref(1.png,メモリ上の配置)
~
メンバ変数Valueは構造体の0バイト目から4バイト分、LowWordは同じく0バイト目から2バイト分、HighWordは2バイト目から2バイト分の位置に配置されます。 参考に、これと同様の結果を得るためのC++コードを次に示します。

          
-
この結果から、この構造体が共用体と同様の機能を得ていることがわかります。 上の図は、その概念図です。 これと同様の結果を得るためのC++コードを次に示します。
 

        

        
 
#code(c){{
#code(c){{
 
#include <iostream>
#include <iostream>
 

        

        
 
using namespace std;
using namespace std;
 

        

        
~
union DoubleWord
struct DWord
 
{
{
+
  unsigned long Value;
+

          
+
  struct
+
  {
 
    unsigned short LowWord;
    unsigned short LowWord;
 
    unsigned short HighWord;
    unsigned short HighWord;
~
  } DWord;
};
-

          
-
union DoubleWord
-
{
-
    unsigned long Value;
-
    DWord         DWord;
 
};
};
 

        

        
 
int main()
int main()
 
{
{
+
  DoubleWord dw;
 

        

        
~
  dw.Value = 0x11223344;
    DoubleWord dw;
 

        

        
~
  cout << " Low word: 0x" << hex << dw.DWord.LowWord << endl;
    dw.Value = 0x11223344;
~
  cout << "High word: 0x" << hex << dw.DWord.HighWord << endl;

          
-
    cout <<  "Low word: 0x" << hex << dw.DWord.LowWord << endl;
-
    cout << "High word: 0x" << hex << dw.DWord.HighWord << endl;
 

        

        
~
  return 0;
    return 0;
 
}
}
 
}}
}}
 

        

        
 
*共用体の有効な利用法
*共用体の有効な利用法
 
これまでのサンプルで、メンバ変数のオフセット値を明示的に設定することで、構造体を共用体と同じように扱ってきました。 しかし、共用体は使う場面が限られていて、たとえ使った場合でも見つけにくいバグを生じてしまうおそれがあるということは、CLSに共用体という概念が存在しないことからもいえることではないかと思います。 しかし、適切な場面で使えば共用体的な概念は有効でバグを減らす可能性も秘めています。
これまでのサンプルで、メンバ変数のオフセット値を明示的に設定することで、構造体を共用体と同じように扱ってきました。 しかし、共用体は使う場面が限られていて、たとえ使った場合でも見つけにくいバグを生じてしまうおそれがあるということは、CLSに共用体という概念が存在しないことからもいえることではないかと思います。 しかし、適切な場面で使えば共用体的な概念は有効でバグを減らす可能性も秘めています。
 

        

        
~
次のサンプルは.NET FrameworkのSystem.Drawing名前空間にも存在する&msdn(netfx,type,System.Drawing.Color){Color構造体};やRGBQUAD構造体に似た構造体を独自に定義したものです。
次のサンプルは.NET FrameworkのSystem.Drawing名前空間にも存在するColor構造体を独自に定義したものです。
 

        

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

        

        
~
[StructLayout(LayoutKind.Explicit)]
namespace StructAndUnion
+
struct Color
 
{
{
~
  [FieldOffset(0)] public uint Value;
    // 構造体で再現した共用体
-
    [StructLayout(LayoutKind.Explicit)]
-
    struct Color
-
    {
-
        [FieldOffset(0)] public System.UInt32 Value;
-
        
-
        [FieldOffset(0)] public System.Byte R;
-
        [FieldOffset(1)] public System.Byte G;
-
        [FieldOffset(2)] public System.Byte B;
-
        [FieldOffset(3)] public System.Byte A;
-
    }
 

        

        
~
  [FieldOffset(0)] public byte R;
    // アプリケーションのエントリーポイントを提供するクラス
~
  [FieldOffset(1)] public byte G;
    class SampleClass
~
  [FieldOffset(2)] public byte B;
    {
~
  [FieldOffset(3)] public byte A;
        [STAThread]
~
}
        static void Main(string[] args)
~

          
        {
~
class SampleClass
            Color c = new Color();
~
{

          
~
  static void Main()
            // 色の値を4バイトの整数で指定
~
  {
            c.Value = 0x80e0c0a0;
~
    Color c = new Color();

          
~

          
            // 各色要素の値表示を表示
~
    // 色の値を4バイトの整数で指定
            Console.WriteLine( "Alpha: 0x" + c.A.ToString("X2") );
~
    c.Value = 0x80e0c0a0;
            Console.WriteLine( "R: 0x" + c.R.ToString("X2") );
~

          
            Console.WriteLine( "G: 0x" + c.G.ToString("X2") );
~
    // 各色要素の値表示を表示
            Console.WriteLine( "B: 0x" + c.B.ToString("X2") );
~
    Console.WriteLine("Alpha: 0x" + c.A.ToString("X2"));
        }
~
    Console.WriteLine("R: 0x" + c.R.ToString("X2"));
    }
+
    Console.WriteLine("G: 0x" + c.G.ToString("X2"));
+
    Console.WriteLine("B: 0x" + c.B.ToString("X2"));
+

          
+
    // RGBAの各値を個別に指定
+
    c.A = 0x40;
+
    c.R = 0xff;
+
    c.G = 0x80;
+
    c.B = 0x00;
+

          
+
    Console.WriteLine("Value: 0x" + c.Value.ToString("X4"));
+
  }
 
}
}
 
}}
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Runtime.InteropServices
+

          
+
<StructLayout(LayoutKind.Explicit)> _
+
Structure Color
+
  <FieldOffset(0)> Public Value As UInteger
+

          
+
  <FieldOffset(0)> Public R As Byte
+
  <FieldOffset(1)> Public G As Byte
+
  <FieldOffset(2)> Public B As Byte
+
  <FieldOffset(3)> Public A As Byte
+
End Structure
+

          
+
Class SampleClass
+
  Shared Sub Main()
+
    Dim c As New Color()
+

          
+
    ' 色の値を4バイトの整数で指定
+
    c.Value = &h80e0c0a0
+

          
+
    ' 各色要素の値表示を表示
+
    Console.WriteLine("Alpha: 0x" + c.A.ToString("X2"))
+
    Console.WriteLine("R: 0x" + c.R.ToString("X2"))
+
    Console.WriteLine("G: 0x" + c.G.ToString("X2"))
+
    Console.WriteLine("B: 0x" + c.B.ToString("X2"))
+

          
+
    ' RGBAの各値を個別に指定
+
    c.A = &h40
+
    c.R = &hff
+
    c.G = &h80
+
    c.B = &h00
+

          
+
    Console.WriteLine("Value: 0x" + c.Value.ToString("X4"))
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
 

        

        
 
#prompt(実行結果){{
#prompt(実行結果){{
 
Alpha: 0x80
Alpha: 0x80
 
R: 0xA0
R: 0xA0
 
G: 0xC0
G: 0xC0
 
B: 0xE0
B: 0xE0
+
Value: 0x400080FF
 
Press any key to continue
Press any key to continue
 
}}
}}
 

        

        
+
Color構造体はA・R・G・Bの四つの独立した値を持つことができます。 この値は、場合によっては4バイトの整数として取得または設定したいということもあります。
+

          
 
#ref(2.png,メモリ上の配置)
#ref(2.png,メモリ上の配置)
 

        

        
~
このように、一つの型でありながら、複数の表現方法があるときなどには共用体の概念は非常に有効です。 StructLayout属性とFieldOffset属性を使用することで、構造体によって共用体と同様の機能を得ると同時に、共用体以上の機能を持った構造体を作ることも可能です。
Color構造体はA・R・G・Bの四つの値を持つことができます。 また、この値は場合によっては4バイトの整数として取得または設定したいということもあります。 このように、一つの型でありながら、複数の表現方法があるときなどには共用体の概念は非常に有効です。
 

        

        
~
最後に、先ほどのColor構造体をプロパティによってプログラムしたサンプルを載せておきます。 同じ機能を実現する場合において、その違いがよくわかると思います。
また、StructLayout属性とFieldOffset属性を使用すると、構造体によって共用体と同様の機能を得ると同時に、共用体以上の機能を持った構造体を作ることも可能です。 最後に、先ほどのColor構造体をプロパティによってプログラムしたサンプルを載せておきます。 同じ機能を実現する場合において、その違いがよくわかると思います。
 

        

        
 
#code(cs){{
#code(cs){{
 
using System;
using System;
 

        

        
~
struct Color
namespace StructAndUnion
 
{
{
~
  private uint val;
    struct Color
+

          
+
  private byte r;
+
  private byte g;
+
  private byte b;
+
  private byte a;
+

          
+
  public uint Value {
+
    get { return val; }
+
    set
 
    {
    {
~
      val = value;
        private System.UInt32 val;
+
      r = (byte)(val & 0xff );
+
      g = (byte)((val >>  8) & 0xff);
+
      b = (byte)((val >> 16) & 0xff);
+
      a = (byte)((val >> 24) & 0xff);
+
    }
+
  }
 

        

        
~
  public byte R {
        private System.Byte r;
~
    get { return r; }
        private System.Byte g;
~
    set
        private System.Byte b;
~
    {
        private System.Byte a;
~
      r = value;

          
~
      val = (uint)(a << 24 | b << 16 | g << 8 | r);
        public System.UInt32 Value
-
        {
-
            get
-
            {
-
                return val;
-
            }
-
            set
-
            {
-
                val = value;
-
                r = (System.Byte)( val & 0xff );
-
                g = (System.Byte)( ( val >>  8 ) & 0xff );
-
                b = (System.Byte)( ( val >> 16 ) & 0xff );
-
                a = (System.Byte)( ( val >> 24 ) & 0xff );
-
            }
-
        }
-

          
-
        public System.Byte R
-
        {
-
            get
-
            {
-
                return r;
-
            }
-
            set
-
            {
-
                r = value;
-
                val = (System.UInt32)( a << 24 | b << 16 | g << 8 | r );
-
            }
-
        }
-

          
-
        public System.Byte G
-
        {
-
            get
-
            {
-
                return g;
-
            }
-
            set
-
            {
-
                g = value;
-
                val = (System.UInt32)( a << 24 | b << 16 | g << 8 | r );
-
            }
-
        }
-
    
-
        public System.Byte B
-
        {
-
            get
-
            {
-
                return b;
-
            }
-
            set
-
            {
-
                b = value;
-
                val = (System.UInt32)( a << 24 | b << 16 | g << 8 | r );
-
            }
-
        }
-

          
-
        public System.Byte A
-
        {
-
            get
-
            {
-
                return a;
-
            }
-
            set
-
            {
-
                a = value;
-
                val = (System.UInt32)( a << 24 | b << 16 | g << 8 | r );
-
            }
-
        }
 
    }
    }
+
  }
 

        

        
~
  public byte G {
    // アプリケーションのエントリーポイントを提供するクラス
~
    get { return g; }
    class SampleClass
+
    set
 
    {
    {
~
      g = value;
        [STAThread]
~
      val = (uint)(a << 24 | b << 16 | g << 8 | r);
        static void Main(string[] args)
-
        {
-
            Color c = new Color();
-

          
-
            // 色の値を4バイトの整数で指定
-
            c.Value = 0x80e0c0a0;
-

          
-
            // 各色要素の値表示を表示
-
            Console.WriteLine( "Alpha: 0x" + c.A.ToString("X2") );
-
            Console.WriteLine( "R: 0x" + c.R.ToString("X2") );
-
            Console.WriteLine( "G: 0x" + c.G.ToString("X2") );
-
            Console.WriteLine( "B: 0x" + c.B.ToString("X2") );
-
        }
 
    }
    }
+
  }
+

          
+
  public byte B {
+
    get { return b; }
+
    set
+
    {
+
      b = value;
+
      val = (uint)(a << 24 | b << 16 | g << 8 | r);
+
    }
+
  }
+

          
+
  public byte A {
+
    get { return a; }
+
    set
+
    {
+
      a = value;
+
      val = (uint)(a << 24 | b << 16 | g << 8 | r);
+
    }
+
  }
 
}
}
-
}}
 

        

        
+
class SampleClass
+
{
+
  static void Main()
+
  {
+
    Color c = new Color();
+

          
+
    // 色の値を4バイトの整数で指定
+
    c.Value = 0x80e0c0a0;
+

          
+
    // 各色要素の値表示を表示
+
    Console.WriteLine("Alpha: 0x" + c.A.ToString("X2"));
+
    Console.WriteLine("R: 0x" + c.R.ToString("X2"));
+
    Console.WriteLine("G: 0x" + c.G.ToString("X2"));
+
    Console.WriteLine("B: 0x" + c.B.ToString("X2"));
+

          
+
    // RGBAの各値を個別に指定
+
    c.A = 0x40;
+
    c.R = 0xff;
+
    c.G = 0x80;
+
    c.B = 0x00;
+

          
+
    Console.WriteLine("Value: 0x" + c.Value.ToString("X4"));
+
  }
+
}
+
}}