C#でGUIDをToStringするときに使用できる書式

C#でGUID(128bit長の一意の識別子)を生成するには、標準ライブラリ内のGuidクラス(System名前空間内)を使用します。

using System;

public static void Main(string[] args)
{
    Guid id = Guid.NewGuid();
    Console.WriteLine(id.ToString());
    // c1b2e279-5d98-45d3-8864-55bcda484695
}

生成したGUIDを文字列として取り出すためにGuidにはToString()メソッドが以下の3種類用意されています。

Signature Description
ToString() デフォルトの文字列取得を行う。(冒頭の通り)
ToString(string format) 書式を指定して文字列を取得する。
ToString(string format, IFormatProvider provider) 普通使わないカスタム書式の指定

このうち、2番目のstring formatを指定するメソッドで、指定できる書式の種類と内容を紹介したいと思います。

指定できる書式と出力

使用できるフォーマットは以下の通り。

書式 使用例 出力結果 説明
"D" もしくは "d" ToString("D") 73a7b7b0-4653-4367-bec0-4f667b936421 桁区切りにハイフン(引数なしToStringと同じ内容)
"N" もしくは "n" ToString("N") 73a7b7b046534367bec04f667b936421 桁区切り無し
"B" もしくは "b" ToString("B") {73a7b7b0-4653-4367-bec0-4f667b936421} Dに加え前後に中括弧
"P" もしくは "p" ToString("P") (73a7b7b0-4653-4367-bec0-4f667b936421) Dに加え前後に丸括弧
"X" もしくは "x" guid.ToString("X") {0x73a7b7b0,0x4653,0x4367,{0xbe,0xc0,0x4f,0x66,0x7b,0x93,0x64,0x21}} int-short-shortの数列と各バイト

Xとかデバッグ目的以外には使用しない変わった出力になります。これはいちいちToBinary()してforeachしないでも同様の結果が得られることを表します。

また、上記以外の文字を指定をするとご丁寧にも以下のメッセージが表示されます。

'System.FormatException' のハンドルされていない例外が mscorlib.dll で発生しました
追加情報: 書式文字列に指定できるのは "D""d""N""n""P""p""B""b""X"、または "x" のみです。

GUIDオブジェクト同士の比較

Guidどうしの比較はCompareToメソッドを使用します。間違ってもToString()した結果を文字列比較しないようにしましょう。(滅茶苦茶効率が悪いです。)

Guid a = Guid.NewGuid();
Guid b = Guid.NewGuid();

int i = a.CompareTo(b); // 比較結果は整数の大小で取得できる。

効率が悪いと言ったので計測結果を以下に示します。

計測内容は、2つのGUIDを作成して同値かどうかを100万回比較しました。結論から言うとToStringで文字列比較すると16倍遅かったです。

internal static void Main(string[] args)
{
    var a = new Stopwatch();
    var b = new Stopwatch();

    for (int i = 0; i < 1000000; i++)
    {
        var aid = Guid.NewGuid();
        var bid = Guid.NewGuid();

        a.Start();
        if (aid.CompareTo(bid) == 0) Console.WriteLine("おなじ");
        a.Stop();

        b.Start();
        if (aid.ToString() == bid.ToString()) Console.WriteLine("おなじ");
        b.Stop();
    }

    Console.WriteLine($"{a.ElapsedMilliseconds}msec"); // 26msec
    Console.WriteLine($"{b.ElapsedMilliseconds}msec"); // 432msec
}

したがって、可能な限りGuid型のまま持ち運んで必要ならToStringしたほうがシステムが効率的ですが、現場ではなぜかToStringしたstring型の値が持ち運ばれる事が多いようです。しかしながら比較を多用する場合、文字列の運搬について多少の考慮をした方がいいかもしれません。

以上です。