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