views:

77

answers:

2

Hi, well I know from my asp.net mvc experience that you can have attributes that handle exceptions (HandleErrorAttribute). As far as I can tell the Controller class has some OnException event which may be integral to this behaviour. However, I want to do something similar in my own code:

dream example:

public String MyProperty
{
    [ExceptionBehaviour(typeof(FormatException), MyExEnum.ClearValue)]
    set
    {
        _thing.prop = Convert.ToThing(value);
    }
}
....

The code above obviously makes very little sense, but is close to the kind of thing I wish to do. I want the attribute on the property set accessor to catch some type of exception and then deal with this in some custom way (or even just swallow it).

Any ideas guys?

A: 

No, that isn't possible unless you use PostSharp or similar. This isn't a standard attribute feature - rather it is something that ASP.NET MVC is adding for you. You don't get it for all attributes.

Marc Gravell
A: 

You can't add an attribute and automagically have exception-handling code added around all calls to a property/method. What you can do, if you're building some sort of framework for this, is look at the type's attributes at runtime and implement your own strategy.

For example, let's say we had this attribute:

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; }
}

And let's say we decorated a property with it:

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); }
    }
}

You can write specific code to look at that attribute and implement the desired behavior:

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;
    }
}

Now I'm not saying that you should do this, and this isn't foolproof code, it's just an example of how you use attributes. What I'm trying to demonstrate here is that (most) attributes can't/don't change compiler behavior (that goes for MVC attributes too), but you might be able to get what you want if you specifically plan for it. You'll always have to use Reflection like this.

Aaronaught