NamingFormatterを作りました

NamingFormatterNamingFormatterというライブラリを作りました。このライブラリは単純で、string.Formatの代替です。使い方や狙いなどを紹介したいと思います。

ソースとNuGet

GitHub: CenterCLR.NamingFormatter
NuGet: CenterCLR.NamingFormatter

ライセンスはApache V2です。PCLのProfile1とProfile259、NET2.0、NET3.5に対応させたので、ほとんどの環境で使用可能です。
(NuGetで簡単に導入するには、VS2010以降が必要です。確認はVS2015以降で行っています)

使い方と狙い

標準のstring.Formatは、引数との突き合せに「インデックス番号」を使用します。しかし、NamingFormatterでは「任意の名前」が使えます。以下は、普通のstring.Formatの例:

var formatted = string.Format(
    "Index0:{0}, Index1:{1}",
    arg0,
    arg1);

このコードの問題は、フォーマット文字列内のインデックス番号が、単なる数値であり、コード上のarg0やarg1と直接的な関係が無い事です。C# 6において、「文字列挿入」という機能が追加されましたが、これはあくまでコンパイル時の評価です。

例えば、フォーマット文字列をユーザーが任意に指定可能となるようなシチュエーションがあると思います。ログ出力のフォーマット指定などが良い例ですが、インデックス番号で指定させると、各番号が何を示すのかが分かりにくくなります。ログ出力の例を示します:

// デフォルトのフォーマット文字列:(App.configで変更可能)
//   "Date: {2:yyyyMMdd}, UserName: {0}, Action: {1}"
var formatString = Properties.Settings.Default.LogFormat;

// フォーマットする(引数との対応付けは?)
var formatted = string.Format(
    formatString,
    userName,
    action,
    date);

上記のように、フォーマット文字列を外部入力によってカスタマイズ可能にした場合、インデックス番号の何番が何かと言う事が非常にわかりにくくなります。このような場合に、NamingFormatterを使うと、以下のようにフォーマット文字列を指定することが出来ます:

using CenterCLR;

// デフォルトのフォーマット文字列:(App.configで変更可能)
//  "Date: {date:yyyyMMdd}, UserName: {userName}, Action: {action}"
var formatString = Properties.Settings.Default.LogFormat;

// フォーマットする(NamedクラスのFormatメソッドを使う)
var formatted = Named.Format(
    formatString,
    Named.Pair("userName", userName),
    Named.Pair("action", action),
    Named.Pair("date", date));

Named.Pairメソッドは、KeyValuePair<string, object>を生成するためのユーティリティメソッドです。もちろん自分でnewしても問題ありません。オーバーロードとしては以下のものがあります。

  • params KeyValuePair<string, object>[] : つまり、上記の例で使用した可変引数対応のメソッドです。
  • IEnumerable<KeyValuePair<string, object>> : LINQの結果を渡してフォーマットさせる場合に使用します。IEqualityComparerを指定してキーの特定方法をカスタマイズする事も出来ます。
  • Dictionary<string, object> : 既に辞書として存在する場合には、これを使うことが出来ます。また、IDictionaryやIReadOnlyDictionaryを使う事も出来ます。
  • 一番基礎的なオーバーロードとして、Func<string, object>を指定するメソッドもあります。このメソッドを使うと、キー名に対応する値を完全にカスタマイズ出来ます。
  • IFormatProviderインターフェイスをフォーマットに使用出来るオーバーロードもあります。

フォーマットオプション

フォーマットオプションとは、インデックス番号の指定だけではなく、書式の形式を追加指定させることが出来る機能です。上記の例でも示しましたが:

// 日付(DateTime構造体)の書式指定を行う
var formatted = Named.Format(
    "Date: {date:yyyy/MM/dd HH:mm:ss.fff}",
    Named.Pair("date", date));

のように、string.Formatで指定する書式指定と同じように、オプションを指定することが出来ます。

あるいは:

// 数値の桁数を指定する
var formatted = Named.Format(
    "Result: {result,10}",
    Named.Pair("result", 123));

のように、桁数指定を行う事も出来ます。もちろん、これらを組み合わせ、更に複数のパラメータを同時に指定させることも可能です。

プロパティのトラバース機能

パラメータに対応するインスタンスがプリミティブ型ではなく、任意のクラスや構造体である場合、パブリックプロパティを探索させることもできます。これは丁度XAMLのバインディング式のように、ドットで区切られた式を書きます:

// DateTimeのプロパティをフォーマット文字列で探索させる
var formatted = Named.Format(
    "Millisec: {date.TimeOfDay.TotalMilliseconds}",
    Named.Pair("date", DateTime.Now));

条件としては、パブリックかつインスタンスプロパティである必要があります。ここではDateTime構造体を例として使用しましたが、もちろん独自のクラスや構造体でも使うことが出来ます。プロパティの指定に失敗している(名前が間違っているなど)場合は、空文字列としてフォーマットされます。


特にカスタマイズ要件がある場合などに、小粒ですが応用できるのではないかと思います。ライセンスもゆるくしてあるので、使ってみて下さい。何か問題があればフィードバックを貰えるとありがたいです。

投稿者:

kekyo

A strawberry red slime mold. Likes metaprogramming. MA. Bicycle rider. http://amzn.to/1SeuUwD