三、特性(Attribute)
3.1、特性的本质
什么是特性?
特性本质是一个类,直接或间接的继承自抽象类Attribute,可以把这个类,用[类名]进行注册标记到类似及类内部的所有成员:约定俗成,默认以Attribute结尾,在进行标记的时候,如果特性类是Attribute结尾的,可以省略不写结尾的Attribute。
特性的约束?
[AttributeUsage(AttributeTargets.All,AllowMultiple = true,Inherited = true)],用来约束特性的特性,AttributeTargets约束用途,AllowMultiple 为true的时候,表示这个特性可以在一个类或者属性等上重复标记,Inherited = true表示这个特性可以被继承。
3.2、特性和注释的区别
注释在编译器编译后是不存在的
3.3、特性的调用
{
//标记好的特性要如何调用?
//要调用特性,必须用到反射
//1、使用反射
//两种方式都可以
Type type = student.GetType();
//Type type = typeof(Student);
//2、获取特性实例,标准用法---先判断,再获取实例
if (type.IsDefined(typeof(CustomAttribute), true)) {
CustomAttribute customAttribute = type.GetCustomAttribute<CustomAttribute>();//执行特性的构造函数
}
//获取属性上的特性
foreach (var prop in type.GetProperties())
{
if (prop.IsDefined(typeof(CustomAttribute), true))
{
CustomAttribute attribute = prop.GetCustomAttribute<CustomAttribute>();
}
}
//获取字段上的特性
foreach (var field in type.GetFields())
{
if (field.IsDefined(typeof(CustomAttribute), true))
{
CustomAttribute attribute = field.GetCustomAttribute<CustomAttribute>();
}
}
//获取方法上的特性
foreach (var mehtod in type.GetMethods())
{
if (mehtod.IsDefined(typeof(CustomAttribute), true))
{
CustomAttribute attribute = mehtod.GetCustomAttribute<CustomAttribute>();
}
}
//特性是一个类,获取到一个实例,--就是得到了一个类的实例
}
定义特性
namespace C_MyAttribute
{
[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = true)]
public class CustomAttribute : Attribute
{
private int _Id { get; set; }
public string _Name { get; set; }
public int _Age;
public CustomAttribute()
{
}
public CustomAttribute(int id)
{
this._Id = id;
}
public CustomAttribute(string name)
{
this._Name = name;
}
public void Do()
{
Console.WriteLine("this is CustomAttribute");
}
}
public class ChildStudent : CustomAttribute
{
}
}
标记特性
namespace C_MyAttribute
{
/// <summary>
/// 这是一个Student类
/// </summary>
// [Obsolete("请不要使用这个了,请使用什么来代替",true)]//系统 --在之前--标记的这玩意还可以影响编译器
//; [Serializable]//可以序列化和反序列化 --类标记了这个特性以后,就可以做序列化
[Custom(id: 234)] //不允许标记两个 对应的无参数构造函数
[Custom] //标记到类
public class Student
{
/// <summary>
///
/// </summary>
[Custom(1234)] //标记到属性
public int Id { get; set; }
public string Name { get; set; }
[CustomAttribute("Richard")] //标记到字段
public string Description;
[CustomAttribute(_Age = 30)] //标记到方法
public void Study()
{
Console.WriteLine($"这里是{this.Name}跟着Eleven老师学习");
}
/// <summary>
/// 提问
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
[return: CustomAttribute] //标记到方法的返回值
public string Answer([CustomAttribute] string name) // [CustomAttribute] //标记到方法的参数
{
return $"This is {name}";
}
[CustomAttribute] //标记到委托
public delegate void StudentDelegate();
//索引器
[CustomAttribute] //标记到索引器
public Index[] values;
}
}
3.4、特性的价值
特性到底可以带来什么?
1.特性可以提供额外信息----本来不具备这个信息的,可以通过特性来增加
2.特性可以提供额外功能----本来不具备这个功能的,可以通过特性来支持这个功能
实例:我定义了一个枚举用来表示用户状态,但是他们的中文含义无法定义,需要在使用的时候,用if去判断输出
namespace C_MyAttribute
{
public enum UserStateEnum
{
/// <summary>
/// 正常
/// </summary>
Normal = 0,
/// <summary>
/// 已冻结
/// </summary>
Frozen = 1,
/// <summary>
/// 已删除
/// </summary>
Deleted = 2
}
}
UserInfo userInfo = new UserInfo()
{
Id = 1,
Name = "Seven",
Age = 20,
Mobile = "18888888888",
State = UserStateEnum.Normal
};
{
//原始做法,根据枚举来判断,得到中文状态
if (userInfo.State == UserStateEnum.Normal)
{
Console.WriteLine("用户状态为正常");
}
else if (userInfo.State == UserStateEnum.Frozen)
{
Console.WriteLine("用户状态为已冻结");
}
else if (userInfo.State == UserStateEnum.Deleted)
{
Console.WriteLine("已删除");
}
//多个页面要使用,则都要做判断
}
如何利用特性来扩展他,让我在得到状态的时候,就可以知道它的中文注释
1、定义特性
namespace C_MyAttribute.Extend
{
/// <summary>
/// 状态描述
/// </summary>
[AttributeUsage(AttributeTargets.Field)]
public class RemarkAttribute : Attribute
{
private string _Desctiption;
public RemarkAttribute(string desctiption)
{
_Desctiption = desctiption;
}
public string GetDescription() => _Desctiption;
}
}
2、在枚举上面标记特性
using C_MyAttribute.Extend;
namespace C_MyAttribute
{
public enum UserStateEnum
{
/// <summary>
/// 正常
/// </summary>
[Remark("正常")]
Normal = 0,
/// <summary>
/// 已冻结
/// </summary>
[Remark("已冻结")]
Frozen = 1,
/// <summary>
/// 已删除
/// </summary>
[Remark("已删除")]
Deleted = 2
}
}
3、封装调用
using C_MyAttribute.Extend;
using System.Reflection;
namespace C_MyAttribute
{
public class DescriptionManager
{
public static string GetDescription(object oValue)
{
Type type = typeof(UserStateEnum);
FieldInfo field = type.GetField(oValue.ToString());
if (field.IsDefined(typeof(RemarkAttribute), true))
{
RemarkAttribute attribute = field.GetCustomAttribute<RemarkAttribute>();
string description = attribute.GetDescription();
Console.WriteLine(description);
return description;
}
else
{
return oValue.ToString();
}
}
}
}
//使用
Console.WriteLine(DescriptionManager.GetDescription(userInfo.State));
对特性的方式进行升级优化
将封装的调用定义为扩展方法,并且限定传入的参数为枚举类型
using C_MyAttribute.Extend;
using System.Reflection;
namespace C_MyAttribute
{
public static class DescriptionManager
{
/// <summary>
/// 静态类中的静态方法,同时第一个参数用this修饰,叫扩展方法
/// </summary>
/// <param name="oValue"></param>
/// <returns></returns>
public static string GetDescription(this Enum oValue)
{
FieldInfo field = oValue.GetType().GetField(oValue.ToString());
if (field.IsDefined(typeof(RemarkAttribute), true))
{
RemarkAttribute attribute = field.GetCustomAttribute<RemarkAttribute>();
string description = attribute.GetDescription();
Console.WriteLine(description);
return description;
}
else
{
return oValue.ToString();
}
}
}
}
对实体中增加一个属性,直接获取枚举对应的中文注释
namespace C_MyAttribute
{
public class UserInfo
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public long QQ { get; set; }
public string Mobile { get; set; }
/// <summary>
/// 用户的状态
/// </summary>
public UserStateEnum State { get; set; }
public string StrDescription
{
get
{
return this.State.GetDescription();
}
}
}
}
{
UserInfo userInfo1 = new UserInfo() {
Id = 1,
Name = "Seven",
Age = 20,
Mobile = "18888888888",
State = UserStateEnum.Normal
};
Console.WriteLine(userInfo1.StrDescription);
}
标签:进阶,标记,C#,Attribute,特性,CustomAttribute,true,public,string
From: https://www.cnblogs.com/SevenDouble/p/18649545