Poll: Attribute Design


I would like to run a quick poll. Which design do you prefer for a set of related attributes and why?


Option #1: Several Attribute Types:


public class AaaaFooAttribute: Attribute { }


public class BbbbFooAttribute: Attribute { }


public class CcccFooAttribute: Attribute { }


public class DdddFooAttribute: Attribute { }


 


Option #2: One Attribute Type and One Enum


public class FooAttribute: Attribute {


     public FooAttribute(FooType type) {}


}


public enum FooType { Aaaa, Bbbb, Cccc, Dddd }


 

Comments (37)

  1. David says:

    It depends on the relationship between the attributes. If they are all modifications to a single behavior, such as the case of an attribute MyWindowMode with the possible modifications of FullScreen, Minimize, Maximize, or Normal, then I prefer one attribute. But if the attributes represent two distinct behaviors, such as MyBinarySerializer or MyXmlSerializer, then two different attributes.

    My basic rule of thumb has been the following:

     If it would be implemented using two different methods, then use two different attributes.

     If it would be implemented using one method with a passed in flag, then use one attribute.

    My reasoning for this, is promote the natural flow of code reading. If attributes are too different than from surrounding code, then it because less efficient to read.

  2. Phillip M. Hoff says:

    I recently had to make a similar decision in a SDK that I’ve been developing.  I started out with your option #1 because it seemed "prettier" at first.  I soon refactored it, however, to use the same form as your option #2.  I had a couple of reasons for doing so.  First, the constructors and named parameters for each of the attribute types ended up being identical, resulting in a lot of duplicated code in both the class definitions as well as any code which manipulates the attributes (which is bad for me, the SDK developer).  Second, I thought that each new class I define is yet another class for the client developer to remember exists.  It’s probably easier to remember how to use one slightly more complicated constructor than multiple slightly less complicated constructors.  Intellisense also a factor here; it makes it easy for the developer to determine what type to pass as the next argument.  It’s not nearly as easy to determine what type one should use to begin with.

    -Phil

  3. Alfred Myers says:

    #2

    In this case, less classes (and documentation and etc) to deal with

  4. Jeff Parker says:

    I think it is going to depend on the situation. Either or are fine but depends what you are going to use it for. For example the Windows Terrarium (Wish they would bring that back) from http://www.windowsforms.net/Applications/application.aspx?PageID=30&tabindex=8 allows you to build a simple dll that contained the logic for your insect plant whatever you put into this massive terrarium.

    Attributes like If it was a Plant or Animal, if it was an Animal was it a Herbavore or a Carnivore. Were like option 1 as they made sense  to be like that. However, Attributes for Carnivore Like Eyesight, Speed, etc were done like option two, which again made perfect sense as they are all grouped together. So I guess it is going to depend on what your doing. Some places doing things a certain way just make more sense.

  5. Right off the top of my head, I’d go with option #2, since that way you can know that the attributes are related in a typed manner and iterate over the options presented.

    However, I could use Option #1 in several other situations.

    I think it depends on how you’ll consume the attribute. Without context, I think this thread will pretty much become a religious debate.

  6. Jonathan Pryor says:

    Option #3: One Attribute Type and Named Properties:

    public class FooAttribute : Attribute {

    public FooAttribute () {}

    public string Aaaa {get; set;}

    public string Bbbb {get; set;}

    public string Cccc {get; set;}

    public string Dddd {get; set;}

    }

    A benefit is that this permits specifying multiple options concisely; compare:

    [assembly: Foo (Aaaa="a", Bbbb="b", Cccc="c")]

    to option 1:

    [assembly: AaaaFooo, BbbbFooo, CcccFooo, DdddFooo]

    and option 2:

    [assembly: Foo (FooType.Aaaa)]

    [assembly: Foo (FooType.Bbbb)]

    [assembly: Foo (FooType.Cccc)]

    Another benefit to option three is that, in many instances, you’ll want additional information anyway.  That is, instead of a "is this attribute present", you’ll have "I potentially need this piece of related information specified by this attribute", and properties provide a nice (if limited) way to provide that related information.

    Slightly unrelated question re: attribute design & usage: Why aren’t arrays within attributes part of the CLS?  I’ve come across a few instances where arrays would be nice, e.g.

    public class PublicHeaderAttribute : Attribute {

    public PublicHeaderAttribute (params string[] headerFiles) {}

    public string[] HeaderFiles {get;}

    }

    // usage:

    [assembly: PublicHeader ("stdio.h", "stdlib.h", "stddef.h")]

    This is potentially nice for code generators, and it’s valid C#, but it’s not CLS compliant, so if the assembly is marked [CLSCompliant(true)] this cannot be used.  I would like to understand why this limitation exists.

  7. In most scenarios I would prefer option #1 because it is more explicit. If the FooAttribute had lots of Aaaa’s and  Bbbb’s, and the differences between the a’s and b’s only would change the behavior of whatever used FooAttribute I might have opted for option #2. As allways, context is king.

  8. Len Weaver says:

    I prefer option two because the attribute in question is likely to have a more general name, and therefore easier to find in intelisense.  I may not know to look for Aaaa, Bbbb, Cccc or Dddd, but I will know to look for FooAttribute, and parameter tips could help me with the parameter.

  9. Maverick says:

    Kris, as long as Aaaa et al can really be sensibly enumerated – e.g. Lock > Read, Write, Shared, … – I would use Option #2, mainly to group the attribute(s) together without having to stick to a strict naming convention, but also reduce clutter in the namespace. Having different classes linke Option #1 is IMO not important, unless the attributes are so different that it makes sense to inherit from one of them, or for one of them to inherit from the other. But really, this is a gray area, ot we would just have public class Attribute(HugeEnum type).

  10. Keith Farmer says:

    I prefer the enum-driven version.  It allows the developer to recall only FooAttribute, relying on intellisense to prompt for FooType.  Further, FooType can be expanded independently without spawning new ZzzzFooAttribute.

    Downside of enum-switching in general:  if the developer wanted to create a method that consumed a subset of FooAttribute, the rejection of ineligible instances is no longer a compile-time feature.  That is, all the information is contained in FooType, whose values are not inspected by the compiler.

    Of course, if we had value parameterization of generics, and generic attributes, I’d prefer:

    FooAttribute<value(FooType)>: Attribute { }

    [FooAttribute<FooType.Aaaa>()]

  11. Dan Glick says:

    Is this poll open to MS people, or external only?

    Personally, I’d pick #2, for two reasons:

    1. Less namespace pollution. No matter how many variants there are, you’re only creating two new types.

    2. More discoverability. With option #2, once I discover FooAttribute, IntelliSense will give me a list of all valid FooTypes.

  12. dono says:

    I think that a more concrete example would be more useful; it is a little too abstract.

    However, here are my preferences.

    Neither.

    As you say, they are a "set of related attributes".

    Why not create a common base class and inherit from that?

    To rewrite your example…

       // Option #3

       public class FooAttribute : Attribute { }

       public class AaaaFooAttribute : FooAttribute { }

       public class BbbbFooAttribute : FooAttribute { }

       public class CcccFooAttribute : FooAttribute { }

       public class DdddFooAttribute : FooAttribute { }

    I think that this more clearly communicates the relatedness of the attributes.

    Also, it allows for easier future maintainability. You can create new related attributes at will.

    With the enum version, to add new types, you will need to modify / extend the current enumeration itself, as well as the single FooAttribute type. I think that we can do better than that.

    However, if I have to choose between the two options that you present, then I would favor Option #1. Granted that the example is abstract, but it seems to me that these are _separate_ but related attributes. Therefore, as with Option #2, grouping them into a single attribute (FooAttribute) does not seem like a very clear design. And of course there is also the same future maintainability issue. Also, what exactly does the parameter provide? Again, it is not a very clear design.

    I am opposed to Option #2 due to 1) maintainability and 2) clarity of design. The only other option is Option #1, which isn’t too bad. But if you permit other options, then I vote for my Option #3.

  13. Garry Trinder says:

    Hi Krzysztof. I would choose an option depending on the possibility that the attributes would be used together to decorate the same class. If the most common scenario is that the developer would use more than one of these attributes in the same class, I would choose Option #1, because the code would look cleaner with more than one attribute applied, I mean the attribute declaration would look smaller. But, if the most common case is that the developer would use only one of these attributes in a class, I would choose Option #2, because it would make the VS intellisense list of attributes smaller and the developer would naturally relate all the variations of the attribute with the single FooAttribute name.

    Julio.

  14. kentcb says:

    Option 2. Why? Because of discoverability. All you have to remember with option 2 is one class. Intellisense will do the rest by pushing the enumeration in your face. Option 1 forces you to choose between several classes without Intellisense aid.

  15. Barry Kelly says:

    In many ways, it seems to me to be analogous to writing several methods versus one method with parameters. It depends! How related are the attributes? Enums are quite discoverable – all the options pop up when you type in the enum name. With multiple methods / attributes, it’s harder to find the related group.

    If the different attributes / methods aren’t closely related, then it would be wrong to conflate them into an enum.

    What about user extensibility? With methods / attributes, one can define new classes / descendants and add new methods / classes that look just like the old ones. With the enums, their baked in. This can be both good and bad – it’s more encapsulated etc, less risk of confusion.

    Another aspect: types for a purpose versus flexible types. Sometimes, people who are beginners to a problem look for something which is the perfect solution. Trouble is, most people’s problems are diverse. This can lead to a large number of "simple" types for solving each particular class of problem, but the overall result is that the solution space is *more* complex because there’s more of it. Beginners and experts alike become frustrated; the first daunted, the other feeling the clutter. In this light, fewer types that are configurable sounds better – leading to the attributes with enum arguments approach. But then – only if it makes sense! A hint: if the attributes would probably start or end with a common prefix or suffix, then it would probably make more sense to use an enum instead.

  16. Chris L says:

    I believe that it’s more intuitive (in most cases) to go with #1. The enum might work if it’s a set of some closely related optional behaviors, but The Class Is The Type, so having an enum to define type is a little awkward. I tend to shy away from enums that are named XxxType. Also, it would require a few more steps with IntelliSense to get your attribute in place.

    "DO use an enum to strongly type parameters, properties, and return values that represent sets of values." (From the Book!)

    IMO, there’s no room in that sentence for strongly typed *types*. And btw, what’s the default (zero) value of such an enum?

    A minor drawback with #1 is that it could possibly clutter the namespace, but since you probably know what you’re looking for, it’s not that big of a deal. And if some of the types are more "advanced" you could do away with them in another namespace. (The Book again…)

  17. pheede says:

    Oh, definately option #2. It just feels so much more organized.

    If the attributes are logically grouped together, i.e.they are all some kind of FooAttribute, then they should also be grouped together by more than just name.

  18. dhananjay singh (dhananjay123@hotmail.com) says:

    I will prefer option 2, It gives logical grouping for related functionality which help in understanding and maintaining the code.It also help dynamically create types on run time.

    But there is one downside for option 2, you have make sure that whenever defination of enum changes you recompile your clients too which uses that enum, cause enum after compilation get converted to const and const get hard coded in IL.

  19. Ken Egozi says:

    I’d go with #2.

    I’ve got two whys for this:

    why #1 (logic): since Aaaa, Bbbb, Cccc, Dddd are all subtypes of Foo (not by behaviuor or inheritance but logically), then they are all Foo but with a different flavour , and to express that intent it is likely to use parametrized attribute.

    why #2 (ease of use): I know I’m looking for a FooAttribute, so after the "[" I hit "F" and want the intellisense to hint me. I do not like to remember all of the Aaaa, Bbbb types. It’s nicer to be hinted to "Foo" by intellisense, and then be hinted to use the parameter while hitting "(" and then be hinted on the subtypes by the Enum. Imagine a next release (WinFx^2 ?) that will add another type. next time I use the attribute, the Enum will tell me of the new type, while in option #1 I’d have to go through all the types in the namespace to find it out (or even to RTFM …)

  20. Gavin Greig says:

    Option #2. First of all, on a gut level, it feels more natural to model what is after all a parameterised design decision with a parameterised attribute. After a little thought, it occurs to me that the IntelliSense story is probably better too – you only have to remember one attribute name and you can then be prompted with possible parameter values, while with Option #1 you would either have to remember all the possible parameter values in order to start typing the right one, or scroll up and down a list to find what you’re looking for.

    Option #1 has some superficial appeal, as at first glance it is less complex to use, but I think in practice this is probably not true.

  21. Pawel Pabich says:

    It’s hard to say. I would like to see the real names and more about what they do. If AAA or BBBB or CCC is the most important part of a class then I will go for option #1 but if their meaning is minor then I will go for option #2.

  22. Martin Ehrlich says:

    Here are some of my thoughts:

    [+/-0] At coding, you gain nothing out of both designs because you have to apply attributes one by one, with the difference, that if you apply two related attributes to the same thing you apply two times the same attribute with different enum-value or two different attributes (only exception would be by using a flags enum).

    [-1] With #1 you have to remember 4 different names instead of 1. Intellisense helps with option #2 because of the enum.

    [+1] If one of the attributes/enums is obsolete you cannot remove it without breaking the api or mark it obsolete with design #2. #1 however does not have this problem.

    [+1] You are more flexible with #1 because you can add optional parameters for special types of attributes later without breaking the api. However with #2 it is slitly more problematic because you apply them to all types at once.

    [+1] #1 is shorter in code and have no repetions of the typename ("foo"), but most things have more than three letters.

    [AaaaFooAttribute]

    class abc {}

    vs.

    [FooAttribute(FooType.Aaaa)]

    class abc {}

    Okay, no more ideas. Makes +2 for #1.

    It is really not easy and I would tend to decide it from case to case. Especially, if there are numerous close related attributes with the same signature, I would tend to choose #2 over #1. Maybe it is easier to decide it by checking the use cases. How often is every type of attribute (probably) used? If there are 4 variations but only one or two are used frequently, maybe it is better to choose #1.

    Oh and another one.

    [+1] Separated attributes allow separate usage because the AttributeUsage attribute can be applied to each class separately. Well, in this case, can the attributes called related?

  23. RonO says:

    If only between these two options, I would choose #1.

    However, I might be tempted to design with a third option depending on a) if the derieved classes shared much common code and b) there was a need to (or value in) refering to the group of attributes by a common class definition.

    public abstract class FooBaseAttribute : Attribute { }

    public class AaaaFooAttribute: FooBaseAttribute { }

    public class BbbbFooAttribute: FooBaseAttribute { }

    public class CcccFooAttribute: FooBaseAttribute { }

    public class DdddFooAttribute: FooBaseAttribute { }

  24. Matt Dunn says:

    Hi Krzysztof,

    My initial reaction was to favour the second option due to its elegance, noting that this design implies all the related attributes must have the same set of properties over time.

    The first option does not have the same limitation as the second, however (taking the  example literally) if there are common properties between the related attributes, then these common properties must be duplicated across the attributes. This could be resolved with attribute inheritance, although this is rare in the BCL, perhaps for good reason (SoapExtensionAttribute is the only example that springs to mind).

    Its also worth considering the two usage scenarios for attributes; decalarative application and discovery. In terms of declarative application, it will be easier for the consumer to discover the available set of related attributes in the IDE using the second option (via Intellisense for the FooType enum). Implementation of discovery will also be cleaner (potentially involving a switch statement based on FooType). The first option will be more difficult for consumers to declaratively apply as its more difficult to discover the related attributes in the IDE, and will also be less elegant to discover (an if statement per related attribute is required).

    Summing up, if different related attributes need to have different sets of properties, then the first option is the only viable, if less elegant, solution. If this flexibility is not required, the second option is preferred in terms of elegance and use.

    Now all thats needed is a crystal ball 🙂

    Cheers,

    Matt

  25. Option 1… it’s much more clear and 2 doesn’t really gain you anything.

  26. dterziev says:

    In my oppinion the two options are applicable in different scenarios.

    Option #1 enables multiple attribute types to be used on a single attribute target:

    [AaaaFooAttribute]

    [BbbbFooAttribute]

    public class AttributeTarget{}

    Option #2, as you have written it, restricts the usage to:

    [FooAttribute(FooType.Aaaa)]

    public class AttributeTarget{}

    If the FooType enum was attributted with [Flags] then option #2 would be equivalent to option #1, and IMHO this would be an easier to understand design (and maybe easier to implement).

    In short, option #2 is my choice.

    Kind regards,

    Dimo

  27. Frank Hileman says:

    No way to decide without any contextual information — what are the real names? How can we possibly decide without knowing what they are used for? It is similar to problem you would have when deciding between multiple classes or a single class and enum, in any scenario. Option 1 is shorter code but option2 easier to discover relationships, more logical.

  28. mike lorengo says:

    In general I prefer option #2 assuming that the attributes are all related or a variation on the general type

    Imagine the PasswordPropertyTextAttribute class had the ability to specify the character used to obscure the text.  I think an enum for the type of charactersused to obscure the text eg

    public class PasswordPropertyTextAttribute: Attribute {

     public PasswordPropertyTextAttribute(CharacterType type) {}

    }

    public enum CharacterType { AsteriskCharacter, QuestionMarkCharacter, BlockCharacter }

    Would be better than

    public class AsteriskPasswordPropertyTextAttibute(), etc

    The reason being that I know I only need to look for one Attribute class, and the variation is controlled by the levers/enumerations around the attribute. If the variation was spread out among multiple classes, it would be more difficult to see all the variations. Start out with the main concept (attribute) and then drill down within it.

    I tried to think of a good example for option #1, but have yet to come up with one.

  29. me says:

    Too often do I hear the argument for syntax design due to Intellisense.

    Intellisense is NOT a feature of a language. It is not part of C#. _Visual C#_, an IDE, utilizes Intellisense.

    However, not everyone uses an IDE. Some use a plain text editor, such as Notepad.

    A common framework utilized by many different languages and many different editors should be designed on clarity of design, maintainability, readability, etc, not features specific to particular IDEs.

    I think it is a mistake to favor option #2 because of Intellisense assistance.

  30. I’m not sure "the attributes are related" is enough to answer: knowing what really make these attributes different (and how different behaviors they could imply) should also usefull.

    By default, I prefer Option #1: in case of attributes, mixing responsibilities in the same class, even if the concerned attributes are related won’t be my first choice.

    Eric

  31. I would suggest a mix between the two options with a little change.

    Where we’ll have option #1 (using a base class) mapping to the current possibilities with the help of option #2, so we’ll end up with something like that:

    public abstract class FooAttribute : Attribute {

        public FooAttribute(FooType type) {}

    }

    public class AaaaFooAttribute: FooAttribute {

       public AaaaFooAttribute : base(FooType.Aaaa){

       }

    }

    public class BbbbFooAttribute: FooAttribute {

       public BbbbFooAttribute: base(FooType.Bbbb){

       }

    }

    public class CcccFooAttribute: FooAttribute {

       public CcccFooAttribute: base(FooType.Cccc){

       }

    }

    public class DdddFooAttribute: FooAttribute {

       public DdddFooAttribute: base(FooType.Dddd){

       }

    }

    public class MyFooAttribute: FooAttribute {

        public MyFooAttribute() : base(FooType.Custom){

    }

    }

    public enum FooType { Aaaa, Bbbb, Cccc, Dddd, Custom }

  32. Vish says:

    I prefer Option 1.

    Even though option 1 seems pretty clumsy to use. It makes life easier for future changes that might be required and not having to rebuild and redeploy for additional capabilities.

    -Vish

  33. Iván says:

    It depends 🙂

    #1 may be easier when using reflection to search for Types or members. And that’s one of the main scenarios for Attibutes.

  34. Mark says:

    I would prefer #1 specifically for the performance implications. Using reflection it is possible to identify if the member is targeted with the custom attribute without expecily creating it however with #2 you need to explicity create the attribute to identify its nature and intent. Saving the developer time is only one of the needs of the SDK design but it also must perform well and clearly state intent. I understand why some would consider #2 better for removing some of the white noise but clearly when evolving the api it seems to be a little more rigid.

  35. Alexander says:

    Hi,

    in simple cases (as in your example) it really doesn’t matter and comes down to "personal style" (which is what you asked for, right?).

    However in more complex scenarios several attribute types will be the way to go as they

    – support different attribute usages

    – can enforce different parametrization rules (such as dependencies between parameters) with respectively designed c’tors

    – can provide different default values, constants, etc.

    – upcoming changes can be applied more locally

    With this assessment in mind I come back to the initial statement and would favour the "several attribute types" approach for consistency.

    Alexander

  36. Jeffro says:

    For those that favor option 2 – what about the tradeoff of design-time vs run-time checking?  With option1, you will have compile-time validation that the option you’ve selected is legit, but with option 2 you could get the following past the compiler:

    [ FooAttribute( (FooType)int.MinValue ) ]

    I thought that having compile-time type checking was a major influence in choosing between design options…?

  37. Weddings says:

    I would like to run a quick poll. Which design do you prefer for a set of related attributes and why? Option #1: Several Attribute Types: public class AaaaFooAttribute: Attribute { } public class BbbbFooAttribute: Attribute { } public class CcccFooAttribute

Skip to main content