特性无处不在
- EF–MVC–WCF–Webservice–UnitTest–IOC–AOP–SuperSocket
- [Obsolete]编译时就有提示 影响了编译器
- [Serializable]对象就可以序列化 影响了程序运行
特性的本质
- 特性就是一个类,直接继承/间接继承自Attribute父类
- 约定俗成用Attribute结尾,标记时就可以省略掉
自定义特性基本语法和使用
自定义特性类(自定义特需要继承Attribute抽象类):
public class CustomAttribute : Attribute {
}
特性的约束使用:
[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = true)]
public class CustomAttribute : Attribute {
}
指定修饰的对象—能否重复修饰–修饰的特性子类是否生效
自定义特性操作
完整自定义特性类:
[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = true)]
public class CustomAttribute : Attribute
{
public CustomAttribute()
{
Console.WriteLine($"{this.GetType().Name} 无参数构造函数执行");
}
public CustomAttribute(int id)
{
Console.WriteLine($"{this.GetType().Name} int参数构造函数执行");
this._Id = id;
}
public CustomAttribute(string name)
{
Console.WriteLine($"{this.GetType().Name} string参数构造函数执行");
this._Name = name;
}
private int _Id = 0;
private string _Name = null;
public string Remark;
public string Description { get; set; }
public void Show()
{
Console.WriteLine($"{this._Id}_{this._Name}_{this.Remark} _ {this.Description}");
}
}
特性修饰元素时用中括号包裹,然后标记到元素,其实就是调用构造函数
然后可以指定属性 字段
AttributeUsage特性,影响编译器运行,
特性修饰类:
[Custom]
[Custom()]
[Custom(Remark = "123")]
[Custom(Remark = "123", Description = "456")]
[Custom(0)]
[Custom(0, Remark = "123")]
[Custom(0, Remark = "123", Description = "456")]
public class Student
{
}
看来上面示例,感觉自定义特性,好像毫无有意,那框架提供特性究竟是怎么产生价值的呢?
[Obsolete][AttributeUsage] 影响了编译器,这属于系统内置,我们搞不了
特性怎么产生价值
首先说结论:其实就是通过反射。
那为什么能通过反射产生价值呢,通过反编译之后,发现特性会在袁术内部生成.custom的东西但是这个东西我们C#访问不到------简直可以理解为,特性没有产生任何变化。
以下是反编译student类IL的截取:
.class public auto ansi serializable beforefieldinit Student
extends [mscorlib]System.Object
{
.custom instance void MyAttribute.CustomAttribute::.ctor()
.custom instance void MyAttribute.CustomAttribute::.ctor()
.custom instance void MyAttribute.CustomAttribute::.ctor() = { Remark=string('123') }
.custom instance void MyAttribute.CustomAttribute::.ctor() = { Remark=string('123') Description=string('456') }
.custom instance void MyAttribute.CustomAttribute::.ctor(int32) = { int32(0) }
.custom instance void MyAttribute.CustomAttribute::.ctor(int32) = { int32(0) Remark=string('123') }
.custom instance void MyAttribute.CustomAttribute::.ctor(int32) = { int32(0) Remark=string('123') Description=string('456') }
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed
{
}
.property instance int32 Id
{
.get instance int32 MyAttribute.Student::get_Id()
.set instance void MyAttribute.Student::set_Id(int32)
.custom instance void MyAttribute.CustomAttribute::.ctor()
}
.method public hidebysig instance string Answer(string name) cil managed
{
.custom instance void MyAttribute.CustomAttribute::.ctor(int32) = { int32(0) }
.custom instance void MyAttribute.CustomAttribute::.ctor(int32) = { int32(0) Remark=string('123') }
.custom instance void MyAttribute.CustomAttribute::.ctor(int32) = { int32(0) Remark=string('123') Description=string('456') }
.param [1]
.custom instance void MyAttribute.CustomAttribute::.ctor()
.maxstack 2
.locals init (
[0] string str)
L_0000: nop
L_0001: ldstr "This is {0}"
L_0006: ldarg.1
L_0007: call string [mscorlib]System.String::Format(string, object)
L_000c: stloc.0
L_000d: br.s L_000f
L_000f: ldloc.0
L_0010: ret
}
那么框架究竟是怎么产生功能的呢?就是反射,在程序运行的时候能够通过反射找到特性,可以从类型、属性、方法、都可以获取特性实例,要求先IsDefined检测,再获取(实例化)。
程序运行时可以找到特性—那就可以发挥特性的作用–提供额外的信息–提供额外的行为。
那该怎么做呢?
特性本身没有用的,这就需要一个第三方InvokeCenter,在这里去主动检测并且使用特性,才能提供功能了。
InvokeCenter类:
public class InvokeCenter
{
public static void ManagerStudent<T>(T student) where T : Student
{
Console.WriteLine($"{student.Id}_{student.Name}");
student.Study();
student.Answer("123");
Type type = student.GetType();
if (type.IsDefined(typeof(CustomAttribute), true))
{
//type.GetCustomAttribute()
object[] oAttributeArray = type.GetCustomAttributes(typeof(CustomAttribute), true);
foreach (CustomAttribute attribute in oAttributeArray)
{
attribute.Show();
//attribute.Description
}
foreach (var prop in type.GetProperties())
{
if (prop.IsDefined(typeof(CustomAttribute), true))
{
object[] oAttributeArrayProp = prop.GetCustomAttributes(typeof(CustomAttribute), true);
foreach (CustomAttribute attribute in oAttributeArrayProp)
{
attribute.Show();
}
}
}
foreach (var method in type.GetMethods())
{
if (method.IsDefined(typeof(CustomAttribute), true))
{
object[] oAttributeArrayMethod = method.GetCustomAttributes(typeof(CustomAttribute), true);
foreach (CustomAttribute attribute in oAttributeArrayMethod)
{
attribute.Show();
}
}
}
}
}
}
StudentVip类继承Student:
[Custom(123, Remark = "VIP", Description = ".Net高级班的学员")]
[Serializable]
public class StudentVip : Student
{
[Custom(123, Remark = "VIP", Description = ".Net高级班的学员")]
public string VipGroup { get; set; }
[Custom(123, Remark = "VIP", Description = ".Net高级班的学员")]
public void Homework()
{
Console.WriteLine("Homework");
}
}
测试运行:
Student student = new StudentVip()
{
Id = 123,
Name = "Alxe"
};
InvokeCenter.ManagerStudent<Student>(student);
控台打印结果:
123_Alxe
这里是Alxe跟着Eleven老师学习
CustomAttribute int参数构造函数执行
CustomAttribute 无参数构造函数执行
CustomAttribute 无参数构造函数执行
CustomAttribute 无参数构造函数执行
CustomAttribute 无参数构造函数执行
CustomAttribute int参数构造函数执行
CustomAttribute int参数构造函数执行
CustomAttribute int参数构造函数执行
123__VIP _ .Net高级班的学员
0__ _
0__ _
0__123 _
0__123 _ 456
0__ _
0__123 _
0__123 _ 456
CustomAttribute int参数构造函数执行
123__VIP _ .Net高级班的学员
CustomAttribute 无参数构造函数执行
0__ _
CustomAttribute int参数构造函数执行
123__VIP _ .Net高级班的学员
CustomAttribute 无参数构造函数执行
0__ _
CustomAttribute int参数构造函数执行
CustomAttribute int参数构造函数执行
CustomAttribute int参数构造函数执行
0__ _
0__123 _
0__123 _ 456