(十二)反射与特性-自定义特性(2)

一、自定义特性

特性是一种特殊的类。
要点:

  • 用户自定义的特性类叫作自定义特性。
  • 所有特性类都派生自 System.Attribute

1、声明自定义特性

声明:

public sealed class MyAttributeAttribute : System.Attribute
{
...
}

由于特性持有目标的信息,所有特性类的公有成员只能是:

  • 字段
  • 属性
  • 构造函数

2、使用特性的构造函数

构造函数的显式隐式声明定义,以及重载等等,规则跟其他类一样。

public MyAtrributeAttribute(string desc, string ver)
{
...
}

3、指定构造函数

[MyAttribute("Holds a value")]//使用一个字符串的构造函数
public int MyField;
[MyAttribute("Version 1.3", "Galen Daniel")]//使用两个字符串的构造函数
public void MyMethod()
{
...
}
//MyAttribute:特性类

特性构造函数要点:

  • 构造函数的实参必须是在编译时能确定值的常量表达式。
  • 如果构造函数没有参数,代码如下:
[MyAttr]
class SomeClass...
[MyAttr()]
class OtherClass...

4、使用构造函数

//命令语句
MyClass mc = new MyClass("Hello", 5);
//声明语句
[MyAttribute("Holds a value")]

特性类和其他类,比较构造函数的使用:

  • 命令语句的实际意义是:“在这里创建新的类。
  • 声明语句的意义是:“这个特性和这个目标相关联,如果需要构造特性,则使用这个构造函数。”

5、构造函数中的位置参数和命名参数

[MyAttribute("An excellent class", Reviewer="Amy McArthur",Ver="0.7.15.33")]
//位置参数:An excellent class
//命名参数:Reviewer="Amy McArthur"、Ver="0.7.15.33"

示例:

public sealed class MyAttributeAttribute : System.Attribute
{
public string Description;
public string Ver;
public string Reviewer;

public MyAttributeAttribute(string desc)//一个形参
{
Description = desc;
}
}

[MyAtrribute("An excellent class", Reviewer="Amy McArthur", Ver="7.15.33")]
class MyClass
{
...
}

二、限制特性的使用

AttributeUsage 特性: 用来限制将特性用在某个目标类型上。

如果希望自定义特性 MyAttribute 只能应用到方法上。

[AttributeUsage(AttributeTarget.Method)]
public sealed class MyAtrributeAttribute : System.Attribute
{
...
}

表-AttributeUsage 的公有属性

名字 意义 默认值
ValidOn 保存能应用特性的目标类型的列表。构造函数的第一个参数必须是 AtrributeTargets 类型的枚举值
Inherited 一个布尔值,它指示特性是否可被装饰类型的派生类所继承 true
AllowMutiple 一个布尔值,指示目标上是否可应用特性的多个实例的 false

1、AtrributeUsage 的构造函数

AtrributeUsage 的构造函数接受单个位置参数,该参数指定了可使用特性的目标类型。它用这个参数来设置 ValidOn 属性,可接受的目标类型是 AttributeTargets 枚举的成员。

可用通过使用按位或运算符来组合使用类型。

[AttributeUsage(AttributeTarget.Method | AtrributeTarget.Constructor)]
public sealed class MyAttributeAttribute : System.Attribute
{
...
}

AttributeTargets 枚举的成员

All Assembly Class Constructor
Delegate Enum Event Field
GenericParameter Interface Method Module
Parameter Property ReterunValue Struct
  • MyAttribute 只能应用到类上。
  • MyAttribute 不会被用用它的类的派生类所继承。
  • 不能在同一个目标上应用 MyAttribute 的多个实例。
[AttributeUsage(AttributeTarget.Class,
			   Inherited = false,
			   AllowMultiple = false
			   )]
public sealed class MyAttribute : System.Attribute
{
...
}

三、自定义特性的最佳实践

1、自定义特性实践

建议自定义特性时:

  • 特性类应用表示目标结构的某种状态。
  • 如果特性需要某些字段,可以通过包含具有位置参数的构造函数来收集数据,可选字段可以用采用命名参数按需初始化。
  • 除了属性之外,不要实现公有方法或其他函数成员。
  • 为了更安全,把特性类声明为 sealed。
  • 在特性声明中使用 AttributeUsage 来显式指定特性目标组。
[AttributeUsage(AttributeTargets.Class)]
public sealed class ReviewCommentAtrribute : System.Attribute
{
public string Description {get; set;}
public string VersionNumber {get;set;}
public string ReviewrID {get;set;}

public ReviewCommentAtrribute(string desc,string ver)
{
Description = desc;
VersionNumber = ver;
}
}

2、访问特性

使用 Type 对象来获取类型信息。Type 的两个方法:IsDefine 和 GetCustomAttributes。

1)使用 IsDefine 方法

可以使用 Type 对象 的 IsDefine 方法来检测某个特性是否应用到了某个类上。

[AttributeUsage(AttributeTargets.Class)]
public sealed class ReviewCommentAttribute : System.Attribute
{...}

[ReviewComent("Check ite out","2.4")]
class MyClass{ }

class Program
{
static void Main()
{
MyClass mc = new MyClass();
Type t = mc.GetType();
bool isDefined = t.IsDenfined(typeof(ReviewCommentAtrribute),false);

if(isDefined)
{
Console.WriteLine($"ReviewComment is applied to type { t.Name }");
}
}
}

输出结果:

ReviewComment is applied tp type MyClass

2)使用 GetCustomAttributes 方法

Type 类的 GetCustomAttributes 方法返回用用到结构上的特性的数组。

  • 实际返回的对象时 object 数组,因此我们必须将它强制转换为相应的特性类型。
  • 布尔参数指定是否搜索继承树来查找特性。
object[] AttArr = t.GetCustomAttributes(false);
  • 调用 GetCustonnAttributes 方法后,每一个与目标相关联的特性的实例就会被创建。
    [AttributeUsage(AttributeTargets.Class)]
    public sealed class MyAtrributeAttribute : System.Attribute
    {
        public string Description { get; set; }
        public string VersionNumber { get; set; }
        public string ReviewerID { get; set; }

        public MyAtrributeAttribute(string desc, string ver)
        {
            Description = desc;
            VersionNumber = ver;
        }
    }

    [MyAtrribute("Check it out","2.4")]
    class MyClass
    { }


    class Program
    {
        static void Main(string[] args)
        {
            Type t = typeof(MyClass);
            object[] AttArr = t.GetCustomAttributes(false);

            foreach(Attribute a in AttArr)
            {
                MyAtrributeAttribute attr = a as MyAtrributeAttribute;
                if(null != attr)
                {
                    Console.WriteLine($"Decription   : { attr.Description }");
                    Console.WriteLine($"Version Number   : { attr.VersionNumber }");
                    Console.WriteLine($"Reviewer ID   : { attr.ReviewerID }");
                }
            }
           
            Console.ReadKey();
        }
    }

输出结果:

Decription : Check it out
Version Number : 2.4
Reviewer ID :

你可能感兴趣的:(CSharp,c#)