Search code examples
c#custom-attribute

When does custom attribute constructor executes?


Intention :

I am writing a business application that uses multiple enums where most of these enums exists in tables in the database too. The problem comes in maintenance when one of the team members or a late developer changes an enum member value at one of the two places leaving the enum unsynced. To solve this problem I am trying to create a custom enum attribute that throws some exception when it finds that an enum values are not in sync.

Implementation :

[AttributeUsage(AttributeTargets.Enum)]
public class EnumSyncAtrribute : Attribute
{

    public EnumSyncAtrribute(Type databaseAccessType, Type enumType))
    {

        // Code that uses that databaseAccessType to access the database to get
        // enum values then compare it to values of enumType , goes here.

    }
}

Then target enum is marked as follows

[EnumSyncAtrribute(typeof(MyDataBaseAccess), typeof(MyEnum))]
public enum MyEnum
{
    value1 = 0,
    value2 = 1,
    value3 = 2
}

Problem :

The problem is this attribute constructor never executes! I have tried replacing Enums with Classes and found that it executes fine, but with Enums, no!

The question is, when custom attributes are used for enums, when does their constructors executes?


Solution

  • 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.
        }
    }