C#特性

1. 什么是特性(Attribute)

1.1 概述

特性(Attribute) 就是在不破坏原有代码的情况下,在代码的元数据上附加一些信息的手段。

2. 特性的使用

2.1 特性的作用

  • attribute是反射的扩充,在结构体上声明一个attribute,本质是将该attribute附加在结构体的元数据上面,需要配合反射来进行访问。

  • 如果要了解attribute,首先还是得理解什么是反射[C#反射详解]。

  • 它允许我们在设计时添加attribute到类、成员等,然后可以在运行时通过反射进行检测(设计时决定运行时的行为),获取它们通过attribute标记的信息,从而根据这些信息做些不同的事情。

2.2 使用示例

特性的使用很简单,在结构声明的上一行,用"[ ]"扩起特性类名即可:

//在结构体上声明一个或多个attribute
//那么这个attribute就会作为一个静态的结构体附加到这个类上
//在程序运行时,框架会通过反射检查attribute标记,去实现相应的功能。
 [Serializable]
 [XmlRoot("MyClass")]
public class Sunshine
{
        public int id;
        ...
        //在一个元素(如类和属性,方法等等)上可以使用一个或多个特性进行修饰。
        //特性可以拥有参数。
         [NonSerialized]
         public string name;

        
 }

3. 预定义的特性

因为特性的灵活与方便,于是类库开发者,则提供了一系类预定义特性。
如[serializable] 标记可序列化的结构,[dllimport] 指示CLR 方法是从DLL导入等, 了解更多微软提供的特性可以查阅官方文档

3.1 Obsolete特性 (简单示例)

当某些旧方法过时了,你不想要在使用这个方法了,可以用Obsolete特性来将程序结构标注为“过时”,并且在代码编译时会显示警告信息。下面是Obsolete特性的使用。

[Obsolete("类已经过时")]
public class MyClass
{
    [Obsolete("方法已经过时,请使用NewSum()")]
    public void Sum()
    {
      //注意: 使用Obsolete特性代码编译时只是显示了警告,但是代码仍然可以执行。
      //而在使用两个参数的重载时,并将Obsolete的第二个参数设置为true时,将会标记为错误。
    }
   
    [Obsolete("Sum(int)", true)]
    public void Sum(int i)
    {
    }
    
    public void NewSum()
    {

    }
}

4. 自定义的特性

4.1 自定义一个特性

C#也允许我们自定义特性,特性其实就是一个类,直接或间接继承自Attribute

using System;

   //自定义特性必须间接或直接继承Attribute类
   //类的名字以Attribute后缀结构
    public class CustomAttribute : Attribute
    {        
    }

4.2 标记自定义特性

约定俗成用Attribute结尾,标记时就可以省略掉;可以用中括号“[ ]”包裹,然后标记到元素,其实就是调用构造函数;

using System;

namespace MyAttribute
{
    [Custom]
    public class Student
    {
        [Custom]
        public int Id { get; set; }
        public string Name { get; set; }
        
        [Custom]
        public void Study()
        {
            Console.WriteLine{this.Name});
        }
    }
}

4.3 调用自定义特性

就像在类中定义了属性,但是属性没有被调用,那么这个属性所蕴含的信息我们并不会知道。同理,仅仅声明了自定义特性,并且应用在某些程序结构上使程序结构和所应用的特性相关联,但是着仅仅相当于一个标识,我们并不没有检索这些特性蕴含的信息。
所以,我们就需要通过反射的方式来访问自定义特性。在上面我们定义并声明好了CustomAttribute特性标记,现在我们通过反射,去读取并且使用这个特性信息。

 //反射获取这个类的信息
Type type = student.GetType();

//IsDefined(Type, Boolean) :检测某个特性是否应用到某个类上
//第一个参数,要接受检查的具体特性, 第二个布尔参数,是否搜索该类的继承链来查找这个特性
if(type.IsDefined(typeof(CustomAttribute), ture))
{
      //GetCustomAttributes(Type, Boolean) :查找并且返回应用到该结构上特性的集合
      //第一个参数,要接受检查的具体特性, 第二个布尔参数,是否搜索该类的继承链来查找这个特性
       object[] oAttributeArray = type.GetCustomAttributes(typeof(CustomAttribute), true);       
       foreach(CustomAttribute attribute in oAttributeArray)
       {
            //调用特性信息或行为
             attribute.Show();
       }
       
       //遍历检查属性是否有特性
       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();
                  }
           }
       }       
}

总结:我们可以通过反射的GetCustomAttributes方法来获取应用到结构上的特性的数组,来获取数据。无论是类,字段或是方法等等结构,我们都可以通过反射得到相应的结构引用,在通过结构的引用调用GetCustomAttributes方法来得到结构上的特性的数组,以此来触发特性。

注意:但是一般我们不会这样使用自定义特性,一般都是配合框架,通过继承框架中为我们写好的特性,进行定制操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值