属性を追加することはできず、プロパティ/メソッドへのすべての呼び出しに例外処理コードが自動的に追加されます。このためのある種のフレームワークを構築している場合にできることは、実行時に型の属性を見て、独自の戦略を実装することです。
たとえば、次の属性があるとします。
public enum ExceptionAction { Throw, ReturnDefault };
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class ExceptionBehaviorAttribute : Attribute
{
public ExceptionBehaviorAttribute(Type exceptionType, ExceptionAction action)
{
this.exceptionType = exceptionType;
this.action = action;
}
public Type ExceptionType { get; private set; }
public ExceptionAction Action { get; private set; }
}
そして、プロパティをそれで装飾したとしましょう:
public interface IHasValue
{
int Value { get; }
}
public class MyClass : IHasValue
{
private string value;
public int Value
{
[ExceptionBehavior(typeof(FormatException),
ExceptionAction.ReturnDefault)]
get { return int.Parse(this.value); }
}
}
特定のコードを記述して、その属性を確認し、目的の動作を実装できます。
public int GetValue(IHasValue obj)
{
if (obj == null)
throw new ArgumentNullException("obj");
Type t = obj.GetType();
PropertyInfo pi = t.GetProperty("Value",
BindingFlags.Instance | BindingFlags.Public);
MethodInfo getMethod = pi.GetGetMethod();
var exbAttributes = (ExceptionBehaviorAttribute[])
getMethod.GetCustomAttributes(typeof(ExceptionBehaviorAttribute), false);
try
{
return obj.Value;
}
catch (Exception ex)
{
var matchAttribute = exbAttributes.FirstOrDefault(a =>
a.ExceptionType.IsAssignableFrom(ex.GetType()));
if ((matchAttribute != null) &&
(matchAttribute.Action == ExceptionAction.ReturnDefault))
{
return default(int);
}
throw;
}
}
これを行うべきだと言っているわけではありません。また、これは誰にでもできるコードではなく、属性の使用方法の単なる例です。私がここで実証しようとしているのは、(ほとんどの) 属性はコンパイラの動作を変更できない/変更しない (MVC 属性にも当てはまる)ことですが、具体的に計画すれば、必要なものを取得できる可能性があります。常にこのように Reflection を使用する必要があります。