Saturday, March 25, 2006 - 13:37

Attributes

No, I didn't really write up 2 posts today - I don't have internet access at my flat at the moment, so I've been blogging offline and then posting at a local internet cafe, which kinda sucks. Sadly, the broadband stuff arrived today, and I was really excited - but it turns out that the landlord has to set up on his laptop, I'm not really sure why, and he can only do that next Saturday. So that'll be another entire week without internet, and now I'm really disappointed. I actually spoke more to my friends here in London when I was in SA, than now that I'm actually in the same city as them. (Yeah, I could just phone them - but I really, really hate using the phone. It's like a phobia, almost).

Anway. On to the next installment of "C# for Interviews". This time, we're dealing with Attributes.

Attributes
Okay, a quick rundown on attributes. Attributes can be added to methods, classes, properties, fields - just about anything, really. It's way to add extra information about the item to the metadata of the assembly, and there's a bunch of predefined attributes (such as 'Serializable') or you can create your own.

Creating your own attributes is pretty simple; the most complex part is determining that an attribute is the best way to go. I haven't used them much; one case where they came in useful was when I had a class with a whole lot of properties, some of which were required and some of which weren't. I tagged each property with a 'Required' attribute, and when the class was populated I'd send it off to a Validator which would check the value of the 'Required' attribute, then check the value of the property to see if it was set.

So let's say we're going to do this. The first step is to create a RequiredAttribute class:


// you can set what language elements (methods, fields, etc)
// you want the attribute to be used for
[AttributeUsage(AttributeTargets.All)]
public class RequiredAttribute : System.Attribute
{
 //this should be private, and we should use properties to access it
 //but for this example, let's just make it public
 public bool Required = false;

 public RequiredAttribute(bool isRequired)
 {
  Required = isRequired;
 }
}


You get named and positional parameters, but we'll just use positional ones for this example.

Now we can tag an item with this attribute::

class MyClass
{
  [Required(true)]
  private int numRows;
}


Note that we could either use 'Required' or 'RequiredAttribute', they'll both work.

Now that we've said that numRows is required, how do we check the value of this attribute in another class? Using reflection, of course. To get a list of all the custom attributes and their values, you can do something like this:

System.Reflection.MemberInfo info = typeof(MyClass);
foreach (object attribute in info.GetCustomAttributes(true))
{
// test the type of the attribute, and deal with it appropriately
}


But this isn't quite what we want to do with the RequiredAttribute. We want to test the value for a particular field:

foreach(FieldInfo field in (typeof(MyClass)).GetFields)
{
 foreach (object attribute in field.GetCustomAttributes(true))
 {
   if (attribute is RequiredAttribute)
   {
    return ((RequiredAttribute)attribute).Required;
   }
 }
}


And it's as simple as that. You get the type of the class, get the fields (or methods, or whatever) belonging to that class, get the customattributes for each field/method/whatever, find the attribute of the correct type, then cast it and get the relevant value.

Labels:

0 Comments:

Post a Comment

<< Home