Properties vs. Attributes

Properties vs. Attributes

Rate This
  • Comments 11

Here is yet another question I got from a C# user recently:

I have a class that represents a business rule. I want to add some rule metadata that could be used by consumers to retrieve a friendlier rule name, description, and anything else that makes sense. Should this information be exposed as an attribute or property on the class?

I would say to absolutely go for a property in this case, for four reasons.

First, properties are highly discoverable. Consumers of this class can use IntelliSense to see that there is a property on the class called "Description" much more easily than they can see that there is an attribute.

Second, properties are much easier to use than attributes. You don't want to muck around with the code to extract strings from metadata attributes unless you really have to.

Third, data such as names and descriptions is highly likely to be localized in the future. Making it a property means that the property getter code can read the string out of a resource, a resource which you can hand off to your localization experts when it comes time to ship the Japanese version.

And fourth, let's go back to basic object-oriented design principles. You are attempting to model something -- in this case, the class is modeling a "business rule".

Note that a business rule is not a class. Nor is a rule an interface. A rule is neither a property nor a method. A rule isn't any programming language construct. A rule is a rule; classes and structs and interfaces and whatnot are mechanisms that we use to implement model elements that represent the desired semantics in a manner that we as software developers find amenable to our toolsBut let's be careful to not confuse the thing being modeled with the mechanisms we use to model it.

Properties and fields and interfaces and classes and whatnot are part of the model; each one of those things should represent something in the model world. If a property of a "rule" is its "description" then there should be something in the model that you're implementing which represents this. We have invented properties specifically to model the "an x has the property y" relationship, so use them.

That's not at all what attributes are for. Think about a typical usage of attributes:

[Obsolete]
[Serializable]
public class Giraffe : Animal
{ ...

Attributes typically do not have anything to do with the semantics of the thing being modeled. Attributes are facts about the mechanisms - the classes and fields and formal parameters and whatnot. Clearly this does not mean "a giraffe has an obsolete and a serializable." This also does not mean that giraffes are obsolete or serializable. That doesn't make any sense. This says that the class named Giraffe is obsolete and the class named Giraffe is serializable.

In short: use attributes to describe your mechanisms, use properties to model the domain.

  • You made a great point. I think most - if not all - C# developers have thought about this decision from time to time. The last sentence is the best guidance I have seen so far. (BTW, this would be a great addition to the .NET Framework Design Guidelines).

    However, I think you did not mention another aspect of attributes. The object oriented programming paradigm in general does not allow you to model "aspects".

    To me, serialization, security, logging etc. are all so-called cross-cutting concerns. Attributes allow you to declaratively embedd them into your code. Although the way they are interpreted varies greatly (compiler, runtime, post-tranformation tool, add-in manager etc.) but I would say that all these "mechanics" (as you called it) achieve the same result: modeling an aspect of your domain.

    Since C# has attributes one could argue that C# allows you to do do a bit of aspect oriented programming (AOP).

  • Eric,

    I use attributes for defining metadata a lot and they served me great so far (of course, I do property- and method-based metadata as well). In my experience, there are cases where the attributes should be preferred, and there are cases when properties have an advantage; I wouldn't go as far as choosing the "cosher" approach. From the top of my head, I'll give you a few reasons for using attributes:

    1) Metadata belongs to a class, not to an instance of a class. You don't need to create an instance of a class only to find out that it shouldn't be used in the current context (yes I am aware that the 'attributes' approach is much slower because of reflection, that's not the point I'm trying to make).

    2) An attribute is a single line of code, which is conveniently located at the top of the class definition. That makes it much easier to understand as compared to looking for a property which might or might not be defined somewhere in the middle of the file.

    3) Ability to specify more than one attribute of the same type could be handy sometimes. Well, it can be emulated with the properties returning arrays or something like it, but it's ugly and besides, you'll have to change every class in the hierarchy when making this change.

    4) Run-time attribute-based code generation - that's a big one!

    The points you mentioned are all good, but I don't think they qualify for being a universal rule as to whether attributes should be used for defining metadata. Let's revisit them:

    1) Properties are highly discoverable - true, but oftentimes you don't need them. And even when you do need them, the solution could be to create a (possibly sealed) property in the base class that would return a value based on the attribute(s).

    2) Properties are much easier to use than attributes - well, to me, the attributes-based approach produces code that is easier to read than the property-based one, and that makes a big difference. Regarding the ease of use, just write the generic "TA FindAttribute<TA, T>() where TA : Attribute" method and never worry again.

    3) Localization - I don't see the issue at all, attribute property's getter can read the localized string from the resources as well, what's the difference?

    4) Object-oriented design principles... what makes you think it's not "object-oriented"? Actually, as I mentioned in the first point, I find the attribute-based approach more solid.

    Finally, let's compare the approaches using the class from the project I'm working on. It has hundreds the actions like the following one (I apologize if the code loses the indentation in the browser, I don't know what the formatting tags are and there is no "preview" button) -

    First, the attribute-based approach. The reader usually groks the whole picture in a matter of seconds.

    [Category("Data")]

    [PopupMenu("Data|Extract Selected Rows")]

    [MainMenu("Data|Extract Selected Rows")]

    [EnabledCondition(NeedsDocument = true, NeedsSelection = true)]

    [Role(AppRole.Editor)]

    [Log(LogUser = true, LogTime = true)]

    public class ExtractSelectedRowsAction : Action

    {

      public override void Run()

      {

         DataUtils.ExtractSelectedRows(Document.Selection);

      }

    }

    Now, the property-based one.

    public class ExtractSelectedRowsAction : Action

    {

      public string Category

      {

         get { return "Data"; }

      }

      public PopupMenuInfo PopupMenuInfo

      {

         get

         {

             return new PopupMenuInfo(new []

                       {

                           "Data",

                           "Extract Selected Rows"

                       });

          }

      }

      public MainMenuInfo MainMenuInfo

      {

         get

         {

             return new MainMenuInfo(new []

                       {

                           "Data",

                           "Extract Selected Rows"

                       });

          }

      }

      public EnabledCondition EnabledCondition

      {

         get

         {

             return new EnabledCondition

             {

                 NeedsDocument = true,

                 NeedsSelection = true

             }

         }

      }

      public AppRole AppRole

      {

         get { return AppRole.Editor; }

      }

      public LogInfo LogInfo

      {

         return new LogInfo

          {

             LogUser = true,

             LogTime = true

          }

      }

      public override void Run()

      {

         DataUtils.ExtractSelectedRows(Document.Selection);

      }

    }

    See what I'm talking about?

  • @Andrew: I assumed we were talking about static properties.

  • One of my favorite bloggers, Eric Lippert , has a great post on the &quot; properties vs. attributes

  • One of my favorite bloggers, Eric Lippert , has a great post on the &quot; properties vs. attributes

  • @Andrew PopupMenu, MainMenu, EnabledCondition ?  Is that a home-grown app framework?  (I ask because it sounds interesting)

  • @CMC

    Yes, that's part of our framework. Actually, since in that case metadata does not belong to an instance of a class, we use the following technique often - UI-related attributes are serialized in the XML files which are read at application start-up (those are plugins) and the UI is populated without loading the actual plugin dlls (the corresponding plugin dll is only loaded when you invoke its action for the first time); that helps a lot since we have 50+ plugins. Of course, you could still achieve the same result with property-based metadata, but attributes make our life much easier in that case.

  • Thank you for submitting this cool story - Trackback from DotNetShoutout

  • Eric, how do you feel about using a [Description] attribute on enum values, to convert them to friendly strings?

    enum MyEnum {

       [Description("First value")]

       Value1,

       [Description("Second value")]

       Value2

    }

  • @Weeble: But aren't static things (properties or methods) among the most un-object oriented features in the language. Consider things like: how they combine with inheritance, there is no polymorphic way of treating all static properties defined in the inheritance chain. You cannot "override" a static property in the base class, you just reintroduce the name. I believe Eric did mean instance properties.

    I also don't find much disagreemente between Andrew and Eric. I find that attributes are the (almost) ideal  replacement of the role that metaclass properties play in dynamic languages. Such roles are almost always metalevel, so it agrees with Eric's suggestion of attributes for implementation mechanism. I believe that attributes should past two questions to be warrant their introduction: "Do I need to conceptually have an instance of the class to access this data?", "Will the data contained be used by the level-0 model code?".

    There are four combinations of answers that, I believe, should help clarify where to put the abstractions.

    If you need the data independent of an instance and that data won't be accessed by the domain model, then it is a metaclass property and attributes are ideal (most of Andrew's attributes fall in here). I also think instance properties are no good here because they force on the metamodel the knowledge of how to construct an instance, something which doesn't belong in there most of the time. But if the domain code does read and takes action depending on this data, then you should consider adding more abstractions to the domain model, as it seems that this data should be instance properties of some new type (representing some model level typification, as opposed to the metalevel typification of Type and such).

    If the data is instance specific, then if it affects the flow of domain code, then it is clearly an instance property, but if it doesn't and it is read only by "mechanisms", then it probably doesn't belong to the domain level protocol (although it may be there for complexity reduction purposes, as is the case for operations like == or GetHashCode or even ToString()) and you should weight the complexity of introducing metaobjects in the solution (objects that represent this instance but with a protocol specific for the metamodel).

    I think these questions are basically a refraiming of the Eric's distinction between mechanisms (metalevel models) and domain (level-0 models).

  • As the last bit says, to me it generally comes down to 'is a' vs. 'has a'.

    The Attributes of a dog include being a mammal, being trainable...

    The Properties of a dog include it's fur color, tricks it knows...

    Property vs. Attribute is a much easier decision than Subclass vs. Interface Implementation vs. Attribute.

    for example the Serializable attribute vs. the ISerializable interface.

Page 1 of 1 (11 items)