13

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
4
  • can you get the attribute using reflection? Commented Jul 4, 2014 at 14:44
  • @KarelFrajtak I'm not sure, I didn't try it yet. Will try in a minute Commented Jul 4, 2014 at 14:45
  • 3
    Your comment // Make sure attribute will get initialized is false. It will only be constructed when the Property is examined (through reflection usually). Commented Jul 4, 2014 at 14:46
  • @Bun yes, you're right. I guess I did not understand the conceipt of attributes well. Commented Jul 4, 2014 at 14:53

2 Answers 2

18

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).

Sign up to request clarification or add additional context in comments.

3 Comments

Marked this as an answer for code samples on how to achieve failure. Thanks a lot!
Not really relevant, but if you target .NET 4.5 or later, there are generic extension methods (need using System.Reflection;), so you can say typeof(Failer).GetProperty("Prop").GetCustomAttribute<FailerAttr>() (single or null) or typeof(Failer).GetProperty("Prop").GetCustomAttributes<FailerAttr>() (all occurences, possibly empty).
@JeppeStigNielsen We're moving to 4.5.1 and I use my own extension methods on 4.0 for that purpose. Thanks for advice, didn't know that
7

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.

2 Comments

So is the constructor code run or not (or does it depend) when the attribute is fetched via reflection, for example with typeof(Failer).GetProperty("Prop").GetCustomAttributes() or similar?
It is executed when you use that piece of reflection, but not at compile time.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.