特性有什么用?
[Obsolete("请不要使用这个类!")]
public class Child: Parent
{
}
在类上面使用 特性,然后重新编译就会有如下输出
如果使用 obsolete 的重载方法
由此
特性可以影响编译
再者:
[Serializable]
public class Child: Parent
{}
表示该类可以序列化
特性可以影响运行
特性是什么?
Attribute:
特性就是直接或者间接继承 于 attribute
约定俗称 特性 都以 Attribute 结尾,在书写的时候就像 MVC 的控制器省略 Collector 一样省略 Attribute
自己写一个特性:
//[AttributeUsage(AttributeTargets.All,AllowMultiple =true)]
class CustomAttribute:Attribute
{
public CustomAttribute()
{
}
public CustomAttribute(int num)
{
}
public CustomAttribute(string str)
{
}
}
使用: 发现给一个类添加多个特性会报错
需要取消代码上的 注释,就可以添加多个重复特性
AttributeUsage 特性是用于特性的特性 ,
第一个参数决定了可以用于什么类型的对象 例如 class 类 ,delegate 委托,Method 方法等
第二个参数决定能否重复修饰
第三个参数 决定 子类中该特性是否生效
[AttributeUsage(AttributeTargets.All,AllowMultiple =true,Inherited =true)]
特性的用法:
[Custom("字符串")]
[Custom(Remark ="随便")]
[Custom(Remark = "随便",Decision ="特性的字段可以这样赋值")]
[return:Custom, Custom(Remark = "返回值也可以重复修饰", Decision = "特性的字段可以这样赋值")]//修饰返回值
public string CommonSay([Custom, Custom(Remark = "参数也可以重复修饰", Decision = "参数也可以重复修饰")] string str)//修饰参数
{
Console.WriteLine("子级的普通方法"+str);
return str;
}
通过反编译工具会发现在IL语言中 特性会 进入到标记的目标内部
这个.custom 我们无法在C#中访问到 ,我们自己写的特性似乎没任何用处
[Serializable] [Obsolete] 是系统自带的特性, 把他们带上反编译会产生什么呢?
用反射来获取特性:
public class InvokeCenter
{
public static void ManagerStudent<T>(T user) where T : Child
{
Console.WriteLine( $"{user.Id}_{user.Name}");
user.Study();
user.Answer();
var type = user.GetType();
//用反射获取类上的Custom 特性
if (type.IsDefined(typeof(CustomAttribute),true))
{
object[] oAttributeArray = type.GetCustomAttributes(typeof(CustomAttribute),true);
foreach (CustomAttribute attr in oAttributeArray)
{
attr.Show();
}
}
//用反射获取属性上的Custom 特性
foreach (var prop in type.GetProperties())
{
if (prop.IsDefined(typeof(CustomAttribute), true))
{
object[] attr = prop.GetCustomAttributes(typeof(CustomAttribute), true);
foreach (CustomAttribute item in attr)
{
item.Show();
}
}
}
//用反射获取属性上的Custom 特性
foreach (var method in type.GetMethods())
{
if (method.IsDefined(typeof(CustomAttribute), true))
{
object[] attr = method.GetCustomAttributes(typeof(CustomAttribute), true);
foreach (CustomAttribute item in attr)
{
item.Show();
}
}
}
}
}
特性代码:
[AttributeUsage(AttributeTargets.All,AllowMultiple =true,Inherited =true)]
class CustomAttribute:Attribute
{
public CustomAttribute()
{
Console.WriteLine($"{this.GetType().Name}的无参构造函数");
}
public CustomAttribute(int num)
{
Console.WriteLine($"{this.GetType().Name}的int构造函数");
this.Id = num;
}
public CustomAttribute(string str)
{
Console.WriteLine($"{this.GetType().Name}的string构造函数");
this.Name = str;
}
public int Id { get; set; }
public string Name { get; set; }
public string Remark { get; set; }
public string Decision { get; set; }
public void Show()
{
Console.WriteLine($"Id:{this.Id},Name:{this.Name},Remark:{this.Remark},Decision:{this.Decision}");
}
}
使用特性的类
[Custom]
[Custom(123)]
[Custom("456")]
[Custom("456",Remark ="哈哈哈哈")]
[Custom("456", Remark = "哈哈哈哈",Decision ="你好!")]
public abstract class Parent
{
private void PrivSaySomeWord()
{
Console.WriteLine("我是一个私有方法!");
}
private string PrivProp { get; set; }
}
[Serializable]
[Obsolete]
[Custom]
public class Child: Parent
{
[Custom]
public int Id { get; set; }
[Custom]
public string Name { get; set; }
[Custom]
public void Study()
{
Console.WriteLine("我在学习!");
}
public void Answer()
{
Console.WriteLine("我在回答!");
}
[Custom("字符串")]
[Custom(Remark ="随便")]
[Custom(Remark = "随便",Decision ="特性的字段可以这样赋值")]
[return:Custom, Custom(Remark = "返回值也可以重复修饰", Decision = "特性的字段可以这样赋值")]//修饰返回值
public string CommonSay([Custom, Custom(Remark = "参数也可以重复修饰", Decision = "参数也可以重复修饰")] string str)//修饰参数
{
Console.WriteLine("子级的普通方法"+str);
return str;
}
}
调用:
var child = new Child();
InvokeCenter.ManagerStudent(child);
Console.ReadLine();
结果:
如上特性本身是没有用的,需要依赖 第三方 例如 上面的类 InvokeCenter 类 去主动检测和使用
特性 是在编译时确定的 :有 string 类型的构造函数 ,但是使用 类的 属性 会报错 ,因为 特性早在编译时确定,不能用变量