Do I need two attribute classes

53 views Asked by At

Let's say I have an attribute like this:

[AttributeUsage(AttributeTargets.All)]
public sealed class LearnAttribute: Attribute
{
    public string FailMessage;
}

Is it possible to define its target in a way that optional ones such as FailMessage are ONLY applicable to property level for a class that I will be decorating it with and LearnAttribute itsself only applicable to class level? or would I need to define two attribute classes?

So for example I could have something like this:

[Learn]
public class Foo
{
    [FailMessage]
    public string BuildingName { get; set; }

    public void Method1()
    {
        Console.WriteLine(nameof(Method1));
    }


}
1

There are 1 answers

1
Guru Stron On BEST ANSWER

Is it possible to define its target in a way that optional ones such as FailMessage are ONLY applicable to property level for a class that I will be decorating it with and LearnAttribute itself only applicable to class level?

No. You can define target only for the attribute class itself so all it's corresponding properties/fields are accessible when it is used. If you really want to you can write a Roslyn analyzer which will do what is needed but I think that this would be a quite confusing API, so I would recommend to stick to the more idiomatic approach with 2 different attributes.

You can create an attribute hierarchy if needed:

[AttributeUsage(AttributeTargets.All)]
public class LearnAttribute : Attribute
{
}

[AttributeUsage(AttributeTargets.Property)]
public sealed class LearnWithFailMessageAttribute : LearnAttribute
{
    public string FailMessage;
}

[Learn]
// [LearnWithFailMessage] // will not compile
public class Foo1
{
    [LearnWithFailMessage(FailMessage = "")]
    public string BuildingName { get; set; }

    public void Method1()
    {
        Console.WriteLine(nameof(Method1));
    }
}

And the LearnWithFailMessage will be accessible by the base class type also:

var propertyInfo = typeof(Foo1).GetProperty(nameof(Foo1.BuildingName));
var customAttribute = propertyInfo.GetCustomAttribute<LearnAttribute>();
Console.WriteLine(customAttribute.GetType().Name); // prints "LearnWithFailMessageAttribute"

Though note that working with attribute hierarchies can have some quirks - see for example this github issue.