例えば、あるクラスのUserが下記の状態だとする。
Normalの場合は「通常ユーザー」を出力
Frozenの場合は「利用中止ユーザー」を出力
Deletedの場合は「退会ユーザー」を出力
public enum UserState
{
Nomal = 0, //通常
Frozen = 1, //利用できない
Deleted = 2 //退会済
}
一般的に、下記の様なswitch文のロジックを組むと思いますが、
これだと、状態を追加するほど、分岐の条件も増やさないといけないので、保守性も非常い低いです。
ここでAttributeを利用すればこれらの事が解決できます。
switch(state)
{
case UserState.Nomal:
Console.WriteLine("通常ユーザー");
break;
case User.Frozen:
Console.WriteLine("利用中止ユーザー");
break;
case User.Deleted:
Console.WriteLine("退会ユーザー");
break;
}
↓Attributeを使用すると
//アトリビュートクラスを作成
public class RemarkAttribute : Attribute
{
public RemarkAttribute(string remark)
{
this._Remark = remark;
}
private string _Remark = null;
public string GetRemark()
{
return this._Remark;
}
}
//Remarkのアトリビュートを追加
public enum UserState
{
[Remark("通常ユーザー")]
Nomal = 0, //通常
[Remark("利用中止ユーザー")]
Frozen = 1, //利用できない
[Remark("退会ユーザー")]
Deleted = 2 //退会済
}
//アトリビュートの機能を作成
public static class RemarkExtension
{
public static string GetRemark(this Enum value)
{
//反射、リフレクションを利用。ネットで調べてください
//valueのタイプを取得
Type type = value.GetType();
//フィールドを取得
FieldInfo field = type.GetField(value.ToString());
//フィールドにRemarkAttributeが定義されていれば
if (field.IsDefined(typeof(RemarkAttribute), true))
{
RemarkAttribute attribute =
(RemarkAttribute)field.GetCustomAttribute(typeof(RemarkAttribute), true);
return attribute.GetRemark();
}
else
{
return value.ToString();
}
}
}
上記を実現すると、下記のようなコードがいらなくなる。
switch(state)
{
case UserState.Nomal:
Console.WriteLine("通常ユーザー");
break;
case User.Frozen:
Console.WriteLine("利用中止ユーザー");
break;
case User.Deleted:
Console.WriteLine("退会ユーザー");
break;
}
↓
//stateがRemarkアトリビュートがある場合、アトリビュートのRemarkをそのまま取得できる、ない場合は、stateそのままになる。
Console.WriteLine(state.GetRemark());
また、UserクラスにAgeというプロパティが存在していて、データベースへ挿入する際に、年齢が18から30までのユーザーしか挿入させないように制限したい。
まず、AgeValidationAttributeというクラスを宣言
public class AgeValidationAttribute : Attribute
{
public AgeValidationAttribute(int min, int max)
{
this._Min = min;
this._Max = _Max;
}
private int _Min = 0;
private int _Max = 0;
//バリデーション
public bool Validate(object value)
{
if (value != null && !string.IsNullOrWhiteSpace(value.ToString()))
{
if (int.TryParse(value.ToString(), out int resut))
{
if (resut > this._Min && resut < this._Max)
{
return true;
}
}
}
return false;
}
}
次はアトリビュートの機能を実現するためのStaticメソッドを宣言
public static class ValidateExtension
{
public static bool Validate(this object value)
{
Type type = value.GetType();
foreach (var prop in type.GetProperties())
{
if (prop.IsDefined(typeof(AgeValidationAttribute), true))
{
AgeValidationAttribute attribute =
(AgeValidationAttribute)prop.GetCustomAttribute(typeof(RemarkAttribute), true);
if (attribute.Validate(prop.GetValue(value)) == false)
{
return false;
}
}
}
return true;
}
}
最後に、プロパティAgeにAgeValidationアトリビュートを追加
[AgeValidation(18,30)]
public int Age { get; set; }
利用時
user.Validate();