アプリ開発をしていると,文字列はリソースで管理することが多い。
しかし,Display や Descriptionなどの属性引数にリソース文字列を使おうとすると,コンパイラ エラー CS0182(属性引数には定数式,typeof 式,または属性パラメーター型の配列の作成式でなければなりません。)となる。
これを回避する方法を考えた。
リソースファイル
こんな感じ。この記事ではTextJapanのみ扱う。
問題のコード
以下のように書くと,コンパイルエラーが発生する。
public enum DisplayResourceCountry { [Display(Name = Properties.Resources.TextJapan)] Japane, } public enum DescriptionResourceCountry { [Description(Properties.Resources.TextJapan)] Japane, }
①DisplayAttributeの場合
DisplayAttributeのResourceTypeプロパティを使う
ResourceTypeプロパティにリソースを設定すると,Nameに指定した値をリソースキーとして認識してリソースから値をとってきてくれる仕組みになっているらしい?。
Nameプロパティには"Text.Japan"とリソースキーを直接打っても良いが,間違ったリソースキーも設定できてしまう。その対策として,nameof()で名前を文字列リテラルとして取得している。nameof演算子はC#6からの機能です。
private const string nameTextJapan = nameof(Properties.Resources.TextJapan); public enum DisplayResourceCountry { [Display(Name = nameTextJapan, ResourceType = typeof(Properties.Resources))] Japane, }
...が,コンボボックスではできなかった。おいおい調査するかも。
コンバータはやはり必要になる。
コンバーターを修正する。
ResourceTypeプロパティ設定されたリソースから,Nameに指定されたリソースキーを取得して返すようGetEnumNameメソッドのを修正した。
public class ComboBoxDisplayConverter : IValueConverter { private string GetEnumName(Enum enumObject) { if (enumObject == null) return ""; FieldInfo fieldInfo = enumObject.GetType().GetField(enumObject.ToString()); object[] attributeArray = fieldInfo.GetCustomAttributes(false); if (attributeArray.Length == 0) { return enumObject.ToString(); } else { DisplayAttribute attribute = attributeArray[0] as DisplayAttribute; if (attribute == null) return string.Empty; if (attribute.ResourceType == null) return attribute.Name; if (attribute.ResourceType.Name != "Resources") return attribute.Name; var resourceManager = new ResourceManager(attribute.ResourceType); if (resourceManager == null) return attribute.Name; return resourceManager.GetString(attribute.Name); } } public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { Enum myEnum = (Enum)value; string description = GetEnumName(myEnum); return description; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { return string.Empty; } }
②DescriptionAttributeの場合
DescriptionAttributeにはResourceTypeプロパティが無いので,扱うリソースファイルが一つの時のみコンバーターで対応可能。
DescriptionAttribute attribute = attributeArray[0] as DescriptionAttribute; if (attribute == null) return string.Empty; var resourceManager = new ResourceManager(typeof(Properties.Resources)); return resourceManager.GetString(attribute.Description);
完成
できた~