I have written a sample as following:
Step 1. Define my custom attribute
[System.Flags()]
public enum MyState
{
State_1 = 0x0001,
State_2 = 0x0002,
State_3 = 0x0004
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
public class MyCustomAttribute : System.Attribute
{
private MyState _state;
public MyState State
{
get { return _state; }
set { _state = value; }
}
public MyCustomAttribute(MyState state)
{
_state = state;
}
}
Step 2. Decorate types with my attribute
[MyCustom(MyState.State_1)]
public class MyClass_1
{
}
[MyCustom(MyState.State_2)]
public class MyClass_2
{
}
public class MyClass_3
{
}
Step 3. Create a Handler class, simulating the behaviors of the CLR
Step 4. Run a test on the code
Output the result:
I wonder if I've done it right or almost, we can discuss this issue. Before the discussion I think we should turn to IL for something, finding how the Attribute affects the type.
Run ILDASM, open the executable file, expand the tree and check MyClass_1 and MyClass_3 for details.
MyClass_1:
MyClass_3:
The difference is quite absolute.
While thinking about how the CLR deals with attributes, how it wrapped additional codes on the existing types, I recall the [Serializable] attribute. If we want a type to be serializable, just decorate the type definition with [Serializable] (and several optional named parameters), then we can serialize the target objects by using a certain formatter (BinaryFormatter, SoapFormatter, XmlSerializer etc.), the same with deserialization. The so-called declarative programming can be seen everywhere in .NET Programming. So I think that the FCL has offered particular classes to handle various attributes, just like the simple architecture shown in my code sample. That's all of my personal opinion, looking forward to other's views.
Step 1. Define my custom attribute
[System.Flags()]
public enum MyState
{
State_1 = 0x0001,
State_2 = 0x0002,
State_3 = 0x0004
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
public class MyCustomAttribute : System.Attribute
{
private MyState _state;
public MyState State
{
get { return _state; }
set { _state = value; }
}
public MyCustomAttribute(MyState state)
{
_state = state;
}
}
Step 2. Decorate types with my attribute
[MyCustom(MyState.State_1)]
public class MyClass_1
{
}
[MyCustom(MyState.State_2)]
public class MyClass_2
{
}
public class MyClass_3
{
}
Step 3. Create a Handler class, simulating the behaviors of the CLR
public
abstract
class
MyAttributeHandler
{
public static void Handle(params Object[] objects)
{
foreach (Object o in objects)
{
if (o.GetType().IsDefined(typeof(MyCustomAttribute), true))
{
Console.WriteLine(o.ToString() +
" is marked with MyCustomAttribute");
// do additional stuff on the object,
// implementation omitted here
}
}
}
}
{
public static void Handle(params Object[] objects)
{
foreach (Object o in objects)
{
if (o.GetType().IsDefined(typeof(MyCustomAttribute), true))
{
Console.WriteLine(o.ToString() +
" is marked with MyCustomAttribute");
// do additional stuff on the object,
// implementation omitted here
}
}
}
}
Step 4. Run a test on the code
class
Program
{
static void Main(string[] args)
{
Object[] objects = { new MyClass_1(), new MyClass_2(), new MyClass_3(), new Object() };
MyAttributeHandler.Handle(objects);
}
}
{
static void Main(string[] args)
{
Object[] objects = { new MyClass_1(), new MyClass_2(), new MyClass_3(), new Object() };
MyAttributeHandler.Handle(objects);
}
}
Output the result:
ConsoleTest
.
MyClass_1 is marked with MyCustomAttribute
ConsoleTest . MyClass_2 is marked with MyCustomAttribute
ConsoleTest . MyClass_2 is marked with MyCustomAttribute
I wonder if I've done it right or almost, we can discuss this issue. Before the discussion I think we should turn to IL for something, finding how the Attribute affects the type.
Run ILDASM, open the executable file, expand the tree and check MyClass_1 and MyClass_3 for details.
MyClass_1:
.
class
public
auto ansi beforefieldinit ConsoleTest.MyClass_1
extends [mscorlib]System.Object
{
.custom instance void ConsoleTest.MyCustomAttribute::.ctor(valuetype ConsoleTest.MyState) = ( 01 00 01 00 00 00 00 00 )
} // end of class ConsoleTest.MyClass_1
extends [mscorlib]System.Object
{
.custom instance void ConsoleTest.MyCustomAttribute::.ctor(valuetype ConsoleTest.MyState) = ( 01 00 01 00 00 00 00 00 )
} // end of class ConsoleTest.MyClass_1
MyClass_3:
.
class
public
auto ansi beforefieldinit ConsoleTest.MyClass_3
extends [mscorlib]System.Object
{
} // end of class ConsoleTest.MyClass_3
extends [mscorlib]System.Object
{
} // end of class ConsoleTest.MyClass_3
The difference is quite absolute.
While thinking about how the CLR deals with attributes, how it wrapped additional codes on the existing types, I recall the [Serializable] attribute. If we want a type to be serializable, just decorate the type definition with [Serializable] (and several optional named parameters), then we can serialize the target objects by using a certain formatter (BinaryFormatter, SoapFormatter, XmlSerializer etc.), the same with deserialization. The so-called declarative programming can be seen everywhere in .NET Programming. So I think that the FCL has offered particular classes to handle various attributes, just like the simple architecture shown in my code sample. That's all of my personal opinion, looking forward to other's views.