Earlier this week, a friend of mine (read his great blog here) had tried to explain me why attributes were useful. We ended up with an extension method that reads attributes of enum values.
Today I have the time to really think about that and I've just realized - this has tons of potential!
Consider the following scenario - you have the following class:
public string GetCityName(long userID)
{
//
// Get data from some datasource...
//
return "Ney York City";
}
And now you're told to add authentication mechanism, so only authenticated users will be able to get the information. What can you do?
Let's create a very simple attribute:
public class AuthenticationRequiredAttribute : Attribute
{
}
We'll use this attribute as a flag - if it's there, authenticate. Otherwise, do not. This is why we don't really need any information there. We'll add the attribute to our method as well:
[AuthenticationRequired]
public string GetCityName(long userID)
{
//
// Get data from some datasource...
//
return "Ney York City";
}
Now we have an attributed method! what's next? Let's create an extension method (remember, we don't want to change the original code). This method will check if the method requires authentication and do that if needed:
public static string GetCityNameAuthenticated(this MyClass myClass, long userId)
{
// Get the method information
MethodInfo mi = typeof(MyClass).GetMethod("GetCityName");
// Check if our attribute appears
object[] atts = mi.GetCustomAttributes(typeof(AuthenticationRequiredAttribute), false);
if (atts != null && atts.Length > 0)
{
// Authenticate
if (!AuthenticateSomehow(userId))
{
// User is not authenticated, raise an exception
throw new UnauthorizedAccessException();
}
}
return myClass.GetCityName(userId);
}
So what have we achieved? we've added authentication to a method without changing its original code! (I know it sounds a bit like AOP, but who cares? it's cool!).
I want to show you another example, maybe even more useful than the last one. It's about expanding enum values data (many thanks to Adrian who's helped me with that). The idea is the same - add an attribute and an extension method that reads it:
public enum Cars
{
[CountryOfOrigin(Name="Japan")]
Mazda,
[CountryOfOrigin(Name="Sweden")]
Volvo,
[CountryOfOrigin(Name="France")]
Peugeot,
[CountryOfOrigin(Name="USA")]
Chrysler
}
public class CountryOfOriginAttribute : Attribute
{
public string Name { get; set; }
}
public static class Extension
{
public static string GetCountryOfOrigin(this Cars car)
{
object[] atts = typeof(Cars).GetField(car.ToString()).GetCustomAttributes(typeof(CountryOfOriginAttribute), false);
if (atts != null && atts.Length > 0)
{
return (atts[0] as CountryOfOriginAttribute).Name;
}
return String.Empty;
}
}
Shay.