キー文字列と StronglyTypedResourceBuilder
埋め込みリソースへのアクセスにはストリーム名が必要だし、マネージドリソースからオブジェクトを取り出すにもキー文字列が必要であるにもかかわらず、データバインディングやリフレクション同様に、.NET ではソースコード上に現れる識別子としてのキー文字列をうまく取り扱うことができない。このあたりは難読化などの問題とあいまって .NET アプリケーション構築の悩みの種となる。
Borland Delphi では string とは別に resourcestring という文字列定数型があり、ソースコード中に、
var ApplicationName: resourcestring = 'RESX ファイルソートツール';
のように文字列定数を宣言しておくことで自動的に文字列テーブルに ApplicationName というキーと対応する文字列が登録される機能がある。*1
これを目指して
public class ResourceString { static ResourceString() { ResourceManager rm = new ResourceManager(typeof(ResourceString)); foreach (FieldInfo fi in typeof(ResourceString).GetFields(BindingFlags.Static)) { fi.SetValue(null, rm.GetString(fi.Name)); } } public readonly string ApplicationName; public readonly string GreetingMessage; // : }
なんてもので適当にごまかしたりもした。*2
.NET 2.0 では System.Resources.Tools.StronglyTypedResourceBuilder というクラスがあり、resgen.exe の /str オプションでこのクラスのもつ機能を呼び出すことができる。これは .resx から .resources を生成するかわりに、.resx に対してタイプセーフな実装テンプレートを自動生成してくれる機能であり、CodeDOM 対応のすべての .NET 対応言語で利用できる。*3
生成されるソースコードは、
public class XXX { protected static ResourceManager rm = new ResourceManager(typeof(XXX)); public static ResourceManager { get { return this.rm; }} public static string ApplicationName { get { return this.rm.GetString("ApplicationName"); }} public static string GreetingMessage { get { return this.rm.GetString("GreetingMessage"); }} public static Bitmap SplashImage { get { return (Bitmao) this.rm.GetObject("SplashImage"); }} }
という感じで、ResourceManager から取得できる要素を適切な型で公開する static property が並ぶもので、あまり期待できたものではない。DotFuscator などの難読化ツールでは、これらの情報をどう扱うのか興味がある*4のだが、たとえば DotFuscator Professinal は 30 万円もする*5わけで、個人では当然ながら仕事でも購入するには数歩引いてしまう価格である。