1. What are the custom attributes?
2. What does compiler do when it finds attributes?
3. What are the positional and named parameters?
4. How to create a custom attribute?
Attributes are a way to associate additional information with a target. Most attributes have no meaning for the compiler; the compiler simply detects the attributes in the source code and emits the corresponding metadata.
Example 1:
[assembly: Attributes.SomeAttr("Applied to assembly")] // Applied to assembly
[module: Attributes.SomeAttr("Applied to module")] // Applied to module
[type: SomeAttr("Applied to type", "27.07.2010", Optional="Named Parameter")]
internal sealed class SomeType<[typevar: SomeAttr("Applied to generic type variable")] T>
{
[field: SomeAttr("Applied to field")]
public Int32 SomeField = 0;
[return: SomeAttr("Applied to return value")]
[method: SomeAttr("Applied to method")]
public Int32 SomeMethod([param: SomeAttr("Applied to parameter")]
Int32 SomeParam)
{
return SomeParam;
}
[property: SomeAttr("Applied to property")]
public String SomeProp
{
[method: SomeAttr("Applied to get accessor method")]
get { return null; }
}
[event: SomeAttr("Applied to event")]
[field: SomeAttr("Applied to compiler-generated field")]
[method: SomeAttr("Applied to compiler-generated add & remove methods")]
public event EventHandler SomeEvent;
}
.class private auto ansi sealed beforefieldinit SomeType<T>
extends [mscorlib]System.Object
{
.custom instance void Attributes.SomeAttr::.ctor(string, string) = { string(‘Applied to type’) string(‘27.07.2010’) Optional=string(‘Named Parameter’) }
.
event [mscorlib]System.EventHandler SomeEvent
{
.addon instance
void Attributes.SomeType`1::add_SomeEvent(class [mscorlib]System.EventHandler)
.removeon instance
void Attributes.SomeType`1::remove_SomeEvent(class [mscorlib]System.EventHandler)
.custom instance
void Attributes.SomeAttr::.ctor(string) = { string(‘Applied to event’) }
}
.method
public hidebysig specialname rtspecialname instance void .ctor() cil managed
{
}
.method
public hidebysig instance int32 SomeMethod(int32 SomeParam) cil managed
{
.custom instance
void Attributes.SomeAttr::.ctor(string) = { string(‘Applied to method’) }
.param [1]
.custom instance
void Attributes.SomeAttr::.ctor(string) = { string(‘Applied to parameter’) }
}
.property instance
string SomeProp
{
.get instance
string Attributes.SomeType`1::get_SomeProp()
.custom instance
void Attributes.SomeAttr::.ctor(string) = { string(‘Applied to property’) }
}
.field
private class [mscorlib]System.EventHandler SomeEvent
{
.custom instance
void Attributes.SomeAttr::.ctor(string) = { string(‘Applied to compiler-generated field’) }
}
.field
public int32 SomeField
{
.custom instance
void Attributes.SomeAttr::.ctor(string) = { string(‘Applied to field’) }
}
}
The constructors’ attributes parameters are called positional and are mandatory. We can also specify properties or fields directly in the attribute declaration; they are called named parameters and are optional.
A custom attribute is simply an instance of a type. Custom attribute classes must be derived, directly or indirectly, from the public abstract System.Attribute class.
Example 2:
namespace Attributes
{
//[AttributeUsage(AttributeTargets.All, )]
public sealed class SomeAttr : Attribute {
private string _name;
private string _creationDate = String.Empty;
public SomeAttr(string name)
{
_name = name;
}
public SomeAttr(string name, string creationDate)
{
_name = name;
_creationDate = creationDate;
}
public string Optional
{
set; get;
}
public override string ToString()
{
return "Name: " + _name + "; Creation date:" + _creationDate + ((Optional == null)? "; Optional: " + Optional : String.Empty);
}
}
}