はじめに
通信文を作成する際にByte配列からInt型の変換、Int型からByte配列の変換する機会はとても多いです。手こずることはないと思いますが、同じような形、さらには一行で変換処理を行えればコードとしてはかなり見やすくなると思い、作成したものを紹介します。
拡張関数について
拡張関数とは、その型のパブリックメソッドのように使うことができる関数です。
基本的な書き方は以下のようになります。
public static class [拡張する型名]+Extend
{
public static [返り値型名] メソッド名(this [拡張する型名] [引数名] )
{
//処理
}
}
staticクラスで宣言をすることができ、一つ目の引数の型名の手前に「this」をつけることによって一つ目の引数の型から派生するメソッドとして扱えます。
public static long ToLong(this int value)
{
return (long)value;
}
//メインから呼び出す。
public static main(string[] args)
{
int ival = 1;
long lval =ival.ToLong();
}
このようにint型には「ToLong」はありませんが、拡張メソッドを作成したおかげで「ToLong」を呼び出すことができます。
Int型からByte配列への変換
メインとしてはBitConverterを利用します。
Intの拡張メソッドとしてByte配列に変換するための「ToBytes」を作成しましょう。
public static byte[] ToBytes(this int value)
{
return BitConverter.GetBytes(value);
}
ただBitConverterを使用してるだけと言われればその通りですが、コードで見た際に、一番左に来る内容が変数名であることに価値があると私は感じています。
またBitConverterの部分を別の処理(リトルエンディアン)などにしてもよいでしょう。
引数2以降も使用できるのでリトルにするかのフラグを用意するのもありですね。
Byte配列からIntへの変換
またBitConverterを利用します。
Byte配列の拡張メソッドとしてIntに変換するための「ToInt」を作成しましょう。
public static int ToInt(this byte[] bytes,ref int curentIndex)
{
int ret = BitConverter.ToInt32(bytes,curentIndex);
curentIndex += sizeof(int);
return ret;
}
こちらは変換元のByte配列以外にも現在の添え字をrefで受け取っています。そのため変換完了後に添え字をずらせる点が良いところです。
「BitConverter」をメインで使用してしまうと変換と変換の間に添え字をずらす処理を入れる必要があり、変換をやっているだけなのに別の処理が挟まりコードとして長くなってしまい、必要でない情報まで入ってしまいます。
しかし拡張を使うことによって、変換する変数名が一番左に行き何をどの順番で変換しているのかがわかりやすくなります。
実装
今回は一旦「int」「double」「DateTime」の変換を用意しました。
「ToBytes」においてはオーバーロードを利用することでどの型からも同じような形で呼び出せるようにします。
public static class UserConverter
{
public static int ToInt(this byte[] bytes,ref int curentIndex)
{
int ret = BitConverter.ToInt32(bytes,curentIndex);
curentIndex += sizeof(int);
return ret;
}
public static double ToDouble(this byte[] bytes, ref int curentIndex)
{
double ret = BitConverter.ToDouble(bytes,curentIndex);
curentIndex += sizeof(double);
return ret;
}
public static DateTime ToDateTime(this byte[] bytes, ref int curentIndex)
{
DateTime ret = DateTime.FromOADate(bytes.ToDouble(ref curentIndex));
return ret;
}
public static byte[] ToBytes(this int value)
{
return BitConverter.GetBytes(value);
}
public static byte[] ToBytes(this double value)
{
return BitConverter.GetBytes(value);
}
public static byte[] ToBytes(this DateTime value)
{
return BitConverter.GetBytes(value.ToOADate());
}
}
使用例
Byteからの変換で添え字をずらしているため、連続して変換を呼び出しても未使用のデータから変換を行ってくれます。
public int Number{get:private set;}
public double Value{get:private set;}
public DateTime Date{get:private set;}
public void ConvertMessage(byte[] message)
{
int index=0;
Number=message.ToInt(ref index);
Value =message.ToDouble(ref index);
Date =message.ToDateTime(ref index);
}