Sunday, June 08, 2014

Understanding the c# Attributes

Symptom:

You see other class declarations in C# using attributes, but you do not quite understand what it does.

Example:

The following is neither a complete nor perfect example of it, but it does demonstrate some few simple points about the C# attributes.

The most important things for you to know about this to me are the following;
  • Attributes, especially the custom attributes you define, goes usually with the Type (i.e., typeof()) , and not with the instance or implementation of a class. This distinction is one of the key in importances in understanding the attributes.
  • As such, it is a way to associate additional information given to the class. Why this could be important is that, for example, the base class can pull the attribute parameters on the behalf of derived classes. You could do this in any number of ways, but this is just another way, and obviously there are more complex use-cases.
  • In the example below I have defined the base base class of SurfBerak which can be derived into any surf break in the world.
  • I have defined two example breaks, one in HalfMoonBay and one in SCW (Santa Cruz West Side). Do note that I do not have anything in these sub-classes, nevertheless if you run the console app example, it will show you proper location and the bottom type just as if I have created a constructor in each class and initialized them with the break name and the bttom type. This is because the break name and the bottom types are specified in the attribute.

    In this case I have written my baseclass, but what if you are using someone else's base (for example a lot of Microsoft's classes) with an ability to specify attributes like I have, then you see a significant potential. You could look at this way; you have just customized the base class with some simple parameters in the attribute.
  • You might be wondering why the break name and the bottom type are specified a bit differently. The break name field is in the constructor parameter of the SurfAttribute class. Microsoft calls this a "positional" parameter. Then there are named parameters. Named parameters are just members of the SurfAttribute class each with a get and a set. Unlike your regular C# class, you should not make the set path as a private. It will not work.
  • You would also notice that in each subclass declaration I say things like [Surf("Hal Moon Bay", bottom = "Sand")]with the keyword of Surf. This is another convention. You can omit the word "Attribute" altogether. 


using System;
using System.Linq;

namespace AttributeCheck
{
    internal class Program
    {
        private static void Main()
        {
            var br = new SurfBreakHMB();
            Console.WriteLine("I have surfed at {0}, Bottom {1}", br.BreakName, br.bottom);
            var br2 = new SurfBreakSCW();
            Console.WriteLine("I have surfed at {0}, Bottom {1}", br2.BreakName, br2.bottom);
        }
    }

    [AttributeUsage(AttributeTargets.All)]
    public class SurfAttribute : Attribute
    {
        public SurfAttribute(string breakName)
        {
            this.breakName = breakName;
        }

        public string breakName { get; set; }
        public string bottom { get; set; } // note that set cannot be private
    }


    public class SurfBreak
    {
        public SurfBreak()
        {
            Type t = GetType();
            object[] ci = t.GetCustomAttributes(true);
            foreach (SurfAttribute at in ci.Where(i => i.GetType() == typeof (SurfAttribute)).Cast())
            {
             BreakN   ame = .breakNatame;
             bot   tom = at.bottom;
            }
        }

        public string BreakName { get; private set; }
        public string bottom { get; private set; }
    }

    [Surf("Hal Moon Bay", bottom = "Sand")]
    public class SurfBreakHMB : SurfBreak
    {
    }

    [Surf("Santa Cruz, West Side", bottom = "Reef")]
    public class SurfBreakSCW : SurfBreak
    {
    }
}

No comments: