While the code to create a custom Attribute is fairly simple, it's very important that you understand what attributes are:
Attributes are metadata compiled into your program. Attributes themselves do not add any functionality to a class, property or module - just data. However, using reflection, one can leverage those attributes in order to create functionality.
So, for instance, let's look at the Validation Application Block, from Microsoft's Enterprise Library. If you look at a code example, you'll see:
/// <summary>
/// blah blah code.
/// </summary>
[DataMember]
[StringLengthValidator(8, RangeBoundaryType.Inclusive, 8, RangeBoundaryType.Inclusive, MessageTemplate = "\"{1}\" must always have \"{4}\" characters.")]
public string Code { get; set; }
From the snippet above, one might guess that the code will always be validated, whenever changed, accordingly to the rules of the Validator (in the example, have at least 8 characters and at most 8 characters). But the truth is that the Attribute does nothing; as mentioned previously, it only adds metadata to the property.
However, the Enterprise Library has a Validation.Validate
method that will look into your object, and for each property, it'll check if the contents violate the rule informed by the attribute.
So, that's how you should think about attributes -- a way to add data to your code that might be later used by other methods/classes/etc.