Cacomania: A way to use and howto use C# attributes

Cacomania

A way to use and howto use C# attributes

Guido Krömer - 7. September 2012 - Tags: , ,

Yesterday I wondered how to associate certain properties of a class which belongs to a database. One solution would have been managing those properties in a list or array, but I thought that this would be a really dirty solution. Adding a pre or posfix to the property name and pregging for it seems to be dirty, too. So I decided to figure out what those square brackets surrounded things above methods, fields, properties... are.

They are called attributes in c#, and new ones can be defined, too. This means, attributes can store meta information, those informations are although retrievable through reflection.

This test class blow has two fields that could be associated with a database and two which are needed for whatever. The attribute "Field" that is defined in the "System.Attribute" extending class above.

namespace AttributesTest
{
    public class Field : System.Attribute { }

    public class MyClass 
    {
        public Object Connection {get; set;}
			
        public string Helper {get; set;}
			
        [Field]
        public string Name {get; set;}
			
        [Field]
        public int Age {get; set;}
    }
}

Thought attributes are objects, an attribute can store more informations. The "MyTypedClass" test class uses the attribute "TypedField" which extends the "Field" attribute from the example above to store the data type of the field used in the database. It would also be possible to store validation rules in the attribute or whatever, but for this sample the data type is enough. The data type itself is defined as an enum with the name "FieldDataType".

namespace AttributesTest
{
    public class TypedField : Field
    {
        public enum FieldDataType 
        {
            Integer,
            Float,
            String,
            Boolean,
            Binary
        }

        public FieldDataType FieldType {get; set;}
            
        public TypedField (FieldDataType type) 
        {
            this.FieldType = type;
        }
    }

    public class MyTypedClass 
    {
        public Object Connection {get; set;}
            
        public string Helper {get; set;}
            
        [TypedField(TypedField.FieldDataType.String)]
        public string Name {get; set;}
            
        [TypedField(TypedField.FieldDataType.Integer)]
        public int Age {get; set;}
            
        [TypedField(TypedField.FieldDataType.Binary)]
        public Object Picture {get; set;}
    }
}

Retrieving those meta information is quite easy using reflections. The "FieldInfo" method loops over all class properties and evaluates the attributes. If an attribute is compatible with "Field" the name of the property gets printed, if the attribute is although compatible with "TypedField" the FieldType (the database data type as mentioned above) get printed, too.


using System;
using System.Reflection;

namespace AttributesTest
{   
    class MainClass
    {
        public static void Main (string[] args)
        {
            Console.WriteLine ("Cacodaemon's C# Attributes test...");
            
            FieldInfo(typeof(MyClass));
            FieldInfo(typeof(MyTypedClass));
        }
        
        public static void FieldInfo(Type type) 
        {
            Console.WriteLine("Class {0}:", type.ToString());
            foreach(PropertyInfo field in type.GetProperties())
            {
                foreach (Attribute attr in field.GetCustomAttributes(true))
                {
                    if (attr is Field) 
                    {
                        Console.Write("\tField name: {0} ", field.Name);
                    }
                    if (attr is TypedField) 
                    {
                        Console.Write("\t ({1})", (attr as TypedField).FieldType.ToString());
                    }
                    Console.Write("\n");
                }
            }
        }
    }
}

Here is a screenshot from the output generated by the example code: Using c# attributes