Thursday, December 26, 2013

Custom Attributes in C#, Part 2

Intro

Back in Part 1 we looked at what attributes are, a reason or two why you might be interested in using them, and how to get their values through reflection. A bit more work was left to your imagination regarding custom attributes. Now it's time to get yer thinkin cap on (maybe it's a beer hat!) and get crackin!

Create Your Own Custom Attribute

Not only can you use built-in .Net framework attributes, you can also create your own custom attributes. I've used them for property validation, object serialization and storage, and many more things. Basically anywhere you need to describe, or give extra information about a code element, you should at least consider using a custom attribute to do the trick. Here's a silly example:

    public enum SillinessFactor
    {
        SuperSilly,
        KindaSilly,
        NotSoSilly,
    }

    public class SillyAttribute : System.Attribute
    {
        public SillinessFactor SillinessFactor { get; set; }

        public SillyAttribute(SillinessFactor sillinessFactor)
        {
            this.SillinessFactor = sillinessFactor;
        }
    }


In the above code we have created an enum to describe the level of silliness that something represents. Just below that enum we have a class called SillyAttribute that derives from the System.Attribute class. Creating your own custom attribute is as simple as that; just derive from System.Attribute. I decided that I would like users to be able to state the level of silliness when applying the Silly attribute to a piece of code, so I coded a constructor that allows the user to pass in one of the valid SillinessFactor enum values. Using this new custom attribute is just as easy as what you saw in the last lesson:

    [Silly(SillinessFactor.SuperSilly)]
    public class SillyClass
    {
    }


Well lookie there pilgrim! We've got a silly class here who is officially marked as being Silly (through the custom attribute), and is assigned a silliness factor of SuperSilly. Yee haw!

Limiting attributes to specific scope(s) 

It's also possible to limit the application of your custom attributes to specific scope(s). Let's say for example that only classes can be Silly, not properties or anything else. How would we accomplish such a monumental feat?

    [System.AttributeUsage(System.AttributeTargets.Class)]
    public class SillyAttribute : System.Attribute
    {
        public SillinessFactor SillinessFactor { get; set; }

        public SillyAttribute(SillinessFactor sillinessFactor)
        {
            this.SillinessFactor = sillinessFactor;
        }
    }


Oh, sweet irony! Yes you accomplish the limitation of attribute scope through another attribute! In the redone sample above, we've told the compiler to limit the Silly attribute to application on classes only. What happens if you try to stick it on an attribute? I could tell you, but then I'd be spoiling all the fun!

What's Next?

There's really not much left with attributes. Experiment with using some of the built-in ones, google around to see how other people use them, and make your own even if it's just a sample. Who knows, you might find a real-world application after you've cemented this little gem in yer noggin.

Resources

No comments:

Post a Comment