共计 4844 个字符,预计需要花费 13 分钟才能阅读完成。
attribute
- 可利用于类型和成员
- 是类的一个实例
- 从 System.Attribute 派生
C# attribute 应用范畴
- 程序集
- 模块
- 类型(类、构造、枚举、接口、委托)
- 字段
- 办法(含结构器)
- 办法参数
- 办法返回值
- 属性
- 事件
- 泛型类型参数
FCL 定义的 Attribute 列举
- Serializable:利用于类型,通知序列化格式化器,一个实例的字段能够呗序列化和反序列化
- Flags:利用于枚举类型,将枚举类型作为一个位标记 (bit flag) 汇合应用
默认自定义的 attribute 类能用于任何指标元素
public class MyAttribute : Attribute | |
{public MyAttribute() | |
{}} | |
[MyAttribute] | |
class Program | |
{[MyAttribute] | |
static void Main(string[] args) | |
{}} |
限定 attribute 的应用范畴:枚举类型
[AttributeUsage(AttributeTargets.Enum, AllowMultiple = false, Inherited = false)] | |
public class MyEnumAttribute : Attribute | |
{public MyEnumAttribute() | |
{}} |
以上代码利用 AttributeUsage 告知编译器定制 attribute 的非法利用范畴,如果将定制 attribute 利用于一个有效指标时将会报错
[MyEnumAttribute] // 正确 | |
public enum MyEnum { } | |
[MyEnumAttribute] // 谬误: 只对枚举无效 | |
class Program | |
{} |
AllowMultiple 和 Inherited
- AllowMultiple:不显示设置为 true 就只能向一个选定指标利用一次
- Inherited:指明在 attribute 利用于基类的时候是否同时利用于派生类和重写办法上
[AttributeUsage(AttributeTargets.Enum, AllowMultiple = false, Inherited = false)] | |
public class MyEnumAttribute : Attribute | |
{public MyEnumAttribute() | |
{}} | |
// 谬误:个性反复 | |
[MyEnumAttribute][MyEnumAttribute] | |
public enum MyEnum { } | |
/*------------------------------*/ | |
[AttributeUsage(AttributeTargets.Enum, AllowMultiple = true, Inherited = false)] | |
public class MyEnumAttribute : Attribute | |
{public MyEnumAttribute() | |
{}} | |
// 正确 | |
[MyEnumAttribute][MyEnumAttribute] | |
public enum MyEnum {} |
定制 attribute 时能够应用结构器获取参数,在应用过程中,必须传递一个编译时常量表达式。传递参数规定:
- Type 类型参数:必须应用 C# 的 typeof 操作符传递
- Object 参数:可传递 int、string 或其它任意常量表达式(包含 null),如果常量表达式为值类型,那么会在运行时结构 attribute 实例的时候对其装箱
示例代码:
/// <summary> | |
/// 自定义 Attribute | |
/// </summary> | |
/// <param name="name"> 援用 string</param> | |
/// <param name="o"> 任意类型,有必要就进行装箱 </param> | |
/// <param name="t">Type 类型 </param> | |
public MyAttribute(string name, Object o, Type t) | |
{ | |
} | |
class Program | |
{[MyAttribute("name", 12, typeof(string))] | |
static void Main(string[] args) | |
{}} |
利用反射查看类型 attribute 扭转代码的行为
[AttributeUsage(AttributeTargets.Enum, AllowMultiple = false, Inherited = false)] | |
public class MyEnumAttribute : Attribute | |
{public MyEnumAttribute() | |
{}} | |
[MyEnumAttribute] | |
public enum MyEnum { } | |
public void Test(Type enumType) | |
{if(enumType.IsDefined(typeof(MyEnumAttribute), false)){// 如果含有 MyEnumAttribute 个性执行以下代码} | |
else | |
{// 否则执行以下代码} | |
} |
应用反射查看办法 attribute 个性
public class MyAttribute : Attribute | |
{public MyAttribute(string name, Object o, Type t) {}} | |
[DebuggerDisplayAttribute("doubleJ", Name = "Name", Target = typeof(Program))] | |
public class Program | |
{[Conditional("Debug")] | |
public void DoSomething() {} | |
[MyAttribute("name", 12, typeof(string))] | |
public static void Main(string[] args) | |
{ShowAttribute(typeof(Program)); | |
var members = typeof(Program).FindMembers( | |
MemberTypes.Method | MemberTypes.Constructor, | |
BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static, | |
Type.FilterName, "*" | |
); | |
foreach (var member in members) | |
ShowAttribute(member); | |
Console.ReadKey();} | |
private static void ShowAttribute(MemberInfo memberInfo) | |
{var attributes = Attribute.GetCustomAttributes(memberInfo); | |
foreach (var attribute in attributes) | |
{Console.WriteLine(attribute.GetType().ToString()); | |
if (attribute is MyAttribute) | |
{ } | |
if (attribute is ConditionalAttribute) | |
{ } | |
DebuggerDisplayAttribute dda = attribute as DebuggerDisplayAttribute; | |
if (dda != null) | |
Console.WriteLine("value = {0}, name = {1},target = {2}", dda.Value, dda.Name, dda.Target); | |
} | |
} | |
} |
运行后果
IsDefined、GetCustomAttributes、GetCustomAttribute 比照
- IsDefined:有一个指定的 Attribute 派生类的实例与指标关联就返回 true,因为不结构任何 Attribute 类的实例所以效率很高
- GetCustomAttributes:返回一个数组,每个元素都是利用于指标的指定 Attribute 类的一个实例。如果不为该办法指定具体的 Attribute,数组中曾经利用的所有 Attribute 的实例,如果没有利用任何 Attribute 类的实例返回空数组
- GetCustomAttribute:返回利用于指标的指定 Attribute 类的一个实例。如果没有则返回 null。如果利用了多个 Attribute 实例,则抛出异样
* 应用 IsDefined 不会调用 Attribute 的结构器,也不会设置它的字段和属性,所以 IsDefined 效率最高,如果想要晓得一个 Attribute 是否利用于一个指标,那么应该抉择应用该办法
条件 Attribute
应用条件 Attribute 后它的执行便会依赖于指定的预处理标识符,如:
[Conditional("DEBUG")] | |
[Conditional("TEST")] | |
public class CondAttribute : Attribute | |
{} |
* 当编译器发现指标元素应用了 Conditional 的一个实例,那么在含有指标元素的代码在进行编译时(以上述代码为例),只有在定义了 TEST 或 DEBUG 符号的前提下,编译器才会在元数据中生成 attribute 信息,尽管如此,但 attribute 类的定义元数据和实现依然存在于程序集中。
重写 Match 和 Equals 实现两个 attribute 实例的匹配
[Flags] | |
public enum Role | |
{ | |
Read = 0x0001, | |
Write = 0x0002 | |
} | |
sealed class RoleAttribute : Attribute | |
{ | |
private Role m_Role; | |
public RoleAttribute(Role role) | |
{this.m_Role = role;} | |
public override bool Match(object obj) | |
{if (obj == null) return false; | |
if (this.GetType() != obj.GetType()) return false; | |
RoleAttribute other = (RoleAttribute)obj; | |
if ((other.m_Role & this.m_Role) != this.m_Role) | |
return false; | |
return true; | |
} | |
public override bool Equals(object obj) | |
{if (obj == null) return false; | |
if (this.GetType() != obj.GetType()) return false; | |
RoleAttribute other = (RoleAttribute)obj; | |
if (other.m_Role != this.m_Role) | |
return false; | |
return true; | |
} | |
public override int GetHashCode() | |
{return (Int32)this.m_Role; | |
} | |
} | |
[RoleAttribute(Role.Read)] | |
class Role1 { } | |
[RoleAttribute(Role.Write)] | |
class Role2 { } | |
public class Program | |
{public static void Main(string[] args) | |
{CanRead(new Role1()); | |
CanRead(new Role2()); | |
Console.ReadKey();} | |
} | |
private static void CanRead(object obj) | |
{Attribute read = new RoleAttribute(Role.Read); | |
Attribute validRole = Attribute.GetCustomAttribute(obj.GetType(), typeof(RoleAttribute), false); | |
if((validRole!=null)&&read.Match(validRole)) | |
Console.WriteLine("{0} can read", obj.GetType()); | |
else | |
Console.WriteLine("{0} can not read", obj.GetType()); | |
} |
输入后果
正文完