Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c# - Throwing exceptions from attribute constructor

I found this article on the subject and tried the following:

public class FailerAttr : Attribute {
    public FailerAttr(string s) {
        throw new Exception("I should definitely fail!");
    }
}

And in unit test project I have the following:

using Microsoft.VisualStudio.TestTools.UnitTesting;

[TestClass]
public class Test {
    [TestMethod]
    public void GoFail() {
        // Make sure attribute will get initialized
        new Failer();
    }

    private class Failer {
        [FailerAttr("")]
        public int Prop { get; set; }
    }
}

When I run the test, it succeeds. So, the questions are:

  1. Why it does not fail?
  2. Is it really a bad idea to throw exceptions from attributes? Because I think I need to.

Some environment info (just in case it's relevant):

  • Unit tests are run via ReSharper's unit test runner (R# v8.2.0.2160)
  • Visual studio v11.0.61030.0
like image 481
Dethariel Avatar asked Jul 04 '14 14:07

Dethariel


2 Answers

Since attributes are part of class definition available to you at runtime (it's also called "metadata" in geekspeak) CLR does not instantiate them unless some part of your program asks for them. This makes sense: why bother spending CPU cycles for something that nobody wants to access?

Because of this, the execution of the constructor will never happen unless you ask for that attribute.

Here is one way to ask for an attribute that would make your program fail:

var attr = Attribute.GetCustomAttribute(typeof(Failer).GetProperty("Prop"), typeof(FailerAttr));

This code makes CLR instantiate the FailerAttr, which triggers the exception.

Demo on ideone.

If you do not know the type of the attribute, you can retrieve all attributes at once with this call:

var allAttributes = Attribute.GetCustomAttributes(typeof(Failer).GetProperty("Prop"));

This causes an exception as well (demo).

like image 191
Sergey Kalinichenko Avatar answered Sep 21 '22 14:09

Sergey Kalinichenko


Attributes are not converted to executable code, they're converted to metadata.

Metadata like this is not used during normal execution, it is only if you start using the metadata, like through reflection, that the attribute type comes back into play.

The constructor or any of the code in the attribute is not executed during compilation. Instead the type and the parameters to the constructor is serialized into the metadata, and only upon inspection using reflection will the constructor actually be executed.

In other words, if you intend this to fail at compile time then you can't.

Try looking for the attributes using reflection, depending on the attribute object is deserialized from the metadata, the constructor may or may not be invoked, but it will definitely not be invoked by just applying it to identifiers.

like image 21
Lasse V. Karlsen Avatar answered Sep 18 '22 14:09

Lasse V. Karlsen