C言語と比較して、C#言語固有と思われるデータ構造、アクセス方法のTipsです。


文字列中のNULL文字

C#言語(というか.NET)では、文字列中にNULL文字(\x00)が入っても良いらしい。
つまり、
string s = "hoge\x00\x00";
s += "hoge";
とすると、string型変数sは、
"hoge\x00\x00hoge"
となる。
が、この文字列に対して、
Debug.Print(s);
とすると、NULL文字以降が無視され、
hoge
としか出力しない。
良いのか????
(Visual C# 2005/2008 Express Edition)


メモリブロック中の整数値取得など

C#には、TCP/IPのパケットヘッダなど、バイト列中の数値取得に便利なSystem.BitConverterクラスがある。
このクラスには、メモリブロックから、(現在のシステムのバイトオーダーにしたがって)数値を取得したり、メモリブロック中のデータの並びを反転させたりするメソッドが含まれている。

たとえば、メモリブロックからLittleEndianの32bit符号なし整数を取得する場合、C言語では
unsigned char buff[] = {0x12, 0x34, 0x56, 0x78};
unsigned long result = 0;
for ( int i=3; i >= 0; i --)
{
    result <<= 8;
    result += buff[i];
}
などとして取得するが、System.BitConverterクラスを使用すると
byte buff[] = {0x12, 0x34, 0x56, 0x78};
// 現在のシステムがBig Endianならデータの並び順を反転させる
if ( !BitConverter.IsLittleEndian )
    Array.Reverse(buff);
// バイト列の内容を符号なし32bit整数として取得する
uint result = BitConverter.ToUInt32( buff, 0 );
で取得できる。

一般的な(と思われる)アプリケーションではこのような処理とは無縁だと思われるのですが、個人的には使用頻度が高い処理なので、かなり有効に使わせてもらっています。
でも、BCDデータには対応していないし、3バイト長の整数データなど、基本データ型の長さと異なる値は扱えないので、結局、昔ながらの処理は残りますが…
そもそも、3バイトや、1.5バイト(12ビット)の符号付整数なんてものを扱う事自体が世間的には特殊なのですが…


ToStringメソッド

IDE(Integrated Development Environment)の変数ウィンドウなどで表示されるクラスの値は、ToStringメソッドの実行結果なので、デバッグ効率が良くなるような表示内容をToStringメソッドで実装すると便利。
ただし、VBではこのような動作にならないらしい。C#への誘導政策と言う事か?


文字列のエンコード

C#言語では、バイト配列から文字列を作成する場合、Encodingクラスを使用し、
byte[] bTemp = { 0x41, 0x82, 0xa0, 0x83, 0x41, 0x88, 0x9f };
Encoding encoding = Encoding.Default; // OSの既定のコードページを使用する
Console.WriteLine(encoding.GetString(bTemp));

byte[] bTemp = { 0x41, 0x82, 0xa0, 0x83, 0x41, 0x88, 0x9f };
Encoding encoding = Encoding.GetEncoding(932); // シフトJISのコードページは932
Console.WriteLine(encoding.GetString(bTemp));
の様に記述する。日本語Windowsであれば、上の二つの処理はどちらも同じ意味になる。
なお、日本国内でも、業務上の必要に迫られて英語版Windowsを使用している環境もあるので、汎用的なアプリケーションを作成しようと思うのなら、既定のエンコードに頼らず、面倒でもコードページを指定したほうが良いと思われる。

ところで、Java言語では、Stringクラスのコンストラクタでバイト配列を指定できる。大抵の場合は、Java言語よりもC#言語の方が簡潔に記述できる場合が多いのだが、文字列のエンコードに関しては、Java言語の方が簡潔な記述が可能となっている。



文字列の有効判定

文字列変数sが有効な文字列か判定する場合
if (s != null && s.Length > 0)
    …
とすることが多いが、string.IsNullOrEmptyメソッドを使用して
if (!string.IsNullOrEmpty(s))
    …
とすればすっきりする。



NULL許容型

int i = null
とすると普通はコンパイルエラーになるが、
int? i = null
と、型名の後ろに「?」をつけると、NULL許容型になり、nullを代入してもエラーにならない。

bool型のデータに対してNULL許容型を使用することによって、
  • 有効 (true)
  • 無効 (false)
のほかに、
  • 未定義 (null)
の三つの状態を持たせる事が出来る。

と、ドキュメントには書かれているが、正直、この例以外の適用方法が良く分らない代物であったが、C# 3.0でサポートされた、LINQのテーブル列定義には必要不可欠な物である。



??演算子

ドキュメントによると、
?? 演算子は、左側のオペランドが null 値でない場合にはこのオペランドを返し、
null 値である場合には右側のオペランドを返します。
とある。

要するに、
if (s == null)
    Console.WriteLine("Unspecified");
else
   Console.WriteLine(s);
というコードが、
Console.WriteLine(s ?? "Unspecified");
と書けるという事になる。

なお、
if (string.IsNullOrEmpty(s))
    Console.WriteLine("Unspecified");
else
   Console.WriteLine(s);
Console.WriteLine(s ?? "Unspecified");
では、s = ""の時の動作が異なる。
最終更新:2007年12月25日 18:06