When Is a Custom Attribute's Constructor Run

When is a custom attribute's constructor run?

When is the constructor run? Try it out with a sample:

class Program
{
static void Main(string[] args)
{
Console.WriteLine("Creating MyClass instance");
MyClass mc = new MyClass();
Console.WriteLine("Setting value in MyClass instance");
mc.Value = 1;
Console.WriteLine("Getting attributes for MyClass type");
object[] attributes = typeof(MyClass).GetCustomAttributes(true);
}

}

[AttributeUsage(AttributeTargets.All)]
public class MyAttribute : Attribute
{
public MyAttribute()
{
Console.WriteLine("Running constructor");
}
}

[MyAttribute]
class MyClass
{
public int Value { get; set; }
}

And what is the output?

Creating MyClass instance
Setting value in MyClass instance
Getting attributes for MyClass type
Running constructor

So, the attribute constructor is run when we start to examine the attribute. Note that the attribute is fetched from the type, not the instance of the type.

When does custom attribute constructor executes?

The attribute is constructed only when you retrieve it (using the GetCustomAttribute function). Otherwise, its construction recipe (constructor overload + positional parameters + properties values) is only stored in the assembly metadata.

In your case, I'd retieve all enum types from the assembly, and check if they have the attribute. Something like that at the startup of your application:

var allEnumTypes = Assembly.GetExecutingAssembly()
.GetTypes()
.Where(t => t.IsEnum);

foreach(var enumType in allEnumTypes)
{
var syncAttr = Attribute.GetCustomAttribute(enumType, typeof(EnumSyncAtrribute)) as EnumSyncAtrribute;
if (syncAttr != null)
{
// Possibly do something here, but the constructor was already executed at this point.
}
}

Custom actions in attribute's constructor

What you are trying to do is not possible. Attributes are meta-data, they are not instantiated at run-time, so your constructor isn't called.

If you step back and think about why, it makes sense. In order for the code you propose to work, the first thing your the run time would have to do before executing any code, is create instances of all attributes. Then you'd run into some fun scenarios like:

 [AttributeB]
public class AttributeA : Attribute{}

[AttributeA]
public class AttributeB : Attribute {}

Which constructor would go first, when would it know to stop, etc? It's reasons like this why the .Net architects decided not to execute Attributes constructors.

Now, to find all the types that are decorated with your attribute, you will need to iterate through all of the types in your assembly from within your Main method (or any other executing method):

 Assembly.GetExecutingAssembly()
.GetTypes()
.Where(t => Attribute.IsDefined(t, typeof(SmartAttribute)))

See get all types in assembly with custom attribute for more discussion on retrieving types decorated with attributes.

Attributes in custom element constructor missing dependent on script tag location

This isn't buggy behavior.

Your first <my-element> is processed by the DOM parser before you define it.

Thus all attributes are known (in the DOM) when the constructor executes.

In general you don't access DOM in the constructor; as it also runs when you do:

 let foo = document.createElement("my-element"); // absolutly no DOM created

Here is a trimmed down example:

<style>
my-element { display:block }
</style>
<my-element id="FOO"> ONE </my-element>
<script>
customElements.define('my-element', class extends HTMLElement {
constructor() {
super();
document.body.append(` ► constructor id:${this.id} ◄ `);
}
connectedCallback() {
document.body.append(` ► connected id:${this.id} ◄ `);
}
});
</script>
<my-element id="BAR"> TWO </my-element>
<my-element id="BAZ"> THREE </my-element>

How do I get the member to which my custom attribute was applied?

Since there seems to be a lot of confusion with respect to how the stack frames and methods work, here is a simple demonstration:

static void Main(string[] args)
{
MyClass c = new MyClass();
c.Name = "MyTest";
Console.ReadLine();
}

class MyClass
{
private string name;

void TestMethod()
{
StackTrace st = new StackTrace();
StackFrame currentFrame = st.GetFrame(1);
MethodBase method = currentFrame.GetMethod();
Console.WriteLine(method.Name);
}

public string Name
{
get { return name; }
set
{
TestMethod();
name = value;
}
}
}

The output of this program will be:

set_Name

Properties in C# are a form of syntactic sugar. They compile down to getter and setter methods in the IL, and it's possible that some .NET languages might not even recognize them as properties - property resolution is done entirely by convention, there aren't really any rules in the IL spec.

Now, let's say for the moment that you had a really good reason for a program to want to examine its own stack (and there are precious few practical reasons to do so). Why in the world would you want it to behave differently for properties and methods?

The whole rationale behind attributes is that they are a kind of metadata. If you want a different behaviour, code it into the attribute. If an attribute can mean two different things depending on whether it's applied to a method or property - then you should have two attributes. Set the target on the first to AttributeTargets.Method and the second to AttributeTargets.Property. Simple.

But once again, walking your own stack to pick up some attributes from the calling method is dangerous at best. In a way, you are freezing your program's design, making it far more difficult for anybody to extend or refactor. This is not the way attributes are normally used. A more appropriate example, would be something like a validation attribute:

public class Customer
{
[Required]
public string Name { get; set; }
}

Then your validator code, which knows nothing about the actual entity being passed in, can do this:

public void Validate(object o)
{
Type t = o.GetType();
foreach (var prop in
t.GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
if (Attribute.IsDefined(prop, typeof(RequiredAttribute)))
{
object value = prop.GetValue(o, null);
if (value == null)
throw new RequiredFieldException(prop.Name);
}
}
}

In other words, you're examining the attributes of an instance that was given to you but which you don't necessarily know anything about the type of. XML attributes, Data Contract attributes, even Attribute attributes - almost all attributes in the .NET Framework are used this way, to implement some functionality that is dynamic with respect to the type of an instance but not with respect to the state of the program or what happens to be on the stack. It is very unlikely that you are actually in control of this at the point where you create the stack trace.

So I'm going to recommend again that you don't use the stack-walking approach unless you have an extremely good reason to do so which you haven't told us about yet. Otherwise you are likely to find yourself in a world of hurt.

If you absolutely must (don't say we didn't warn you), then use two attributes, one that can apply to methods and one that can apply to properties. I think you'll find that to be much easier to work with than a single super-attribute.



Related Topics



Leave a reply



Submit