M12i.

学術書・マンガ・アニメ・映画の消費活動とプログラミングについて

JP1/AJS2ユニット定義パーサAPIをC#向けにポーティングした

すでに何度も紹介してきたJP1/AJS2ユニット定義パーサAPIですが、最近取り組んでいるC#のお勉強の「実践編」としてC#向けにポーティングしてみました。リポジトリこちら

サンプル・コードをご覧になればお分かりのように使い方はほとんどかわりません。途中から「忠実に写すこと」を完全に放棄してしまい空(そら)で移植─つまりは単なる実装しなおしをしはじめてしまったのですが。。。

// 文字列もしくはファイルからユニット定義をパースする
IUnit u = Unit.FromString(
	"unit=XXXX0000,,,;\n" +
	"{   ty=n;\n" +
	"    cm=\"comment text...\";\n" +
	"    unit=XXXX1000,,,;\n" +
	"    {   ty=n;\n" +
	"        unit=XXXX1100,,,;{ty=pj;sc=\"x:\\path\\to\\script\";prm=\"param list\";tho=0;}\n" +
	"        unit=XXXX1200,,,;{ty=j;sc=\"/path/to/script\";prm=\"param list\";tho=1;}\n" +
	"    }\n" +
	"    unit=XXXX2000,,,;{ty=j;sc=\"/path/to/script\";tho=2;}\n" +
	"}");

// 直属の下位ユニットのうち名前が1000で終わるものすべて
IEnumerable<IUnit> childrenNameEndsWith1000 = u.Query(Q.Children.NameEndsWith("1000"));
// ...そのうち1件だけ(存在しない場合は例外をスローする)
IUnit child0NameEndsWith1000 = u.Query(Q.Children.NameEndsWith("1001").One());

// 直属・非直属の下位ユニットのうち種別がUNIXジョブであるもののscパラメータすべて
IEnumerable<IParameter> paramsScOfDescendantsTypeIsUnixJob = u.Query(Q
	.Descendants.TypeIs(UnitType.UnixJob).TheirParameters.NameIs("sc"));
// ...そのうち1件だけ(存在しない場合はnullを返す)
IParameter param0ScOfDescendantsTypeIsUnixJob = u.Query(Q
	.Descendants.TypeIs(UnitType.UnixJob)
	.TheirParameters.NameIs("sc").One(true));

実装している中で「便利だなぁ」と思ったものの第1はなんといっても先日の記事でも言及したyield returnです。この遅延評価IEnumerableをつくるための糖衣構文の威力は凄まじかったです。これは今以ってJavaには存在しないものです(代替物としてがんばってつくってみたものについてはこちら)。

そして第2・3はやはりラムダ式による呼び出しリスト作成やLINQです。Javaにもバージョン8でラムダ式が導入されましたが、Javaの本質的にインターフェースとその実装たる匿名内部クラスの組合せという非常にシンプルな成り立ちに対して、C#のそれはマルチキャスト機能を有する独自のクラスです。そうであるがゆえに便利な面と不便な面があるように思いますが・・・今回は便利な面が目立ちました。

LINQについてはStream APIと比べられるほどまだ使い込めていません。いずれきっちり比較したいものです。

m12i.hatenablog.com

m12i.hatenablog.com