zoukankan      html  css  js  c++  java
  • C#基础知识之特性

    一、什么是特性

      个人理解:特性本质上也是有一种类,通过添加特性,就可以实例化这个特性类;添加特性就是在类、方法、结构、枚举、组件等上面加一个标签,使这些类、方法、结构、枚举、组件等具有某些统一的特征,用以满足相关的需求。比如:方法的异常捕捉,你是否还在某些可能出现异常的地方(例如数据库的操作、文件的操作等)经常使用try...catch。这个时候如果使用特性,就可以大大减少方法里面的try...catch的使用。你只需要定义一个专门捕捉异常的特性类ExceptionExAttribute,然后给这个特性类做些特殊处理,比如给它增加一个AOP拦截的功能。那么在可能出现异常的方法名称上面加上一个[ExceptionEx]特性标签,这个方法就具有自动捕捉异常的能力。

    官方定义:特性是用于在运行时传递程序中各种元素(比如类、方法、结构、枚举、组件等)的行为信息的声明性标签。您可以通过使用特性向程序添加声明性信息。一个声明性标签是通过放置在它所应用的元素前面的方括号([ ])来描述的。特性(Attribute)用于添加元数据,如编译器指令和注释、描述、方法、类等其他信息。.Net 框架提供了两种类型的特性:预定义特性和自定义特性。

    二、规定特性(Attribute)

      规定特性(Attribute)的语法如下:

      [attribute(positional_parameters, name_parameter = value, ...)]   element

      特性(Attribute)的名称和值是在方括号内规定的,放置在它所应用的元素之前。positional_parameters 规定必需的信息,name_parameter 规定可选的信息。

      1、预定义特性(Attribute)

        .Net 框架提供了三种预定义特性:

      •   AttributeUsage
      •   Conditional
      •   Obsolete

       (1)AttributeUsage

          预定义特性 AttributeUsage 描述了如何使用一个自定义特性类。它规定了特性可应用到的项目的类型。规定该特性的语法如下:

    [AttributeUsage(
       validon,//参数 validon 规定特性可被放置的语言元素。它是枚举器 AttributeTargets 的值的组合。默认值是 AttributeTargets.All。
       AllowMultiple=allowmultiple,//参数 allowmultiple(可选的)为该特性的 AllowMultiple 属性(property)提供一个布尔值。如果为 true,则该特性是多用的。默认值是 false(单用的)。
       Inherited=inherited//参数 inherited(可选的)为该特性的 Inherited 属性(property)提供一个布尔值。如果为 true,则该特性可被派生类继承。默认值是 false(不被继承)。
    )]
    using System;
    using System.Diagnostics;
    namespace RabbitMQTest
    {
        class Program
        { 
            static void Main(string[] args)
            {
                //通过反射查看TestPersonAttribute
                Type type = typeof(TestPersonAttribute);
                var person = type.GetCustomAttributes(typeof(PersonAttribute), false);
                foreach (PersonAttribute each in person)
                {
                    Console.WriteLine("Name:{0}", each.Name);
                    Console.WriteLine("Age:{0}", each.Age);
                }
                Console.ReadKey();
            }
        }
        /// <summary>
        /// 使用AttributeUsage自定义特性PersonAttribute
        /// </summary>
        [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
        public class PersonAttribute : Attribute
        {
            public PersonAttribute(string name, int age)
            {
                this.Name = name;
                this.Age = age;
            }
            public string Name { get; set; }
            public int Age { get; set; }
        }
        /// <summary>
        /// 使用自定义特性
        /// </summary>
        [Person("Dachong", 20)]
        [Person("Tiger", 25)]  
        public class TestPersonAttribute
        {
    
        }
    } 
    View Code

       (2) Conditional

          Conditional这个预定义特性要好好介绍一下,因为项目中还是会用到的。#if/#endif是经常用来让同一份代码生成不同的编译结果,最常见的就是debug版和release版。但是这在实际应用中并不是非常友好,因为它们容易被滥用,其代码也难以理解或调试。举个例子: 

    static void Function1()
    {
      #if DEBUG
                Console.WriteLine("In Function 1.");
      #endif
    }  

        最终会在release环境下编译后留下一个Function1()空方法,虽然在release版本中Function1()什么也不做,但是Function1()方法的加载、JIT编译和调用仍然有些开销。C#为此添加了一个Conditional特性,该特性可以标识出某种环境设置下某个方法是否应该被调用。使用这种方式来描述条件编译要比#if/#endif更加清晰。这个预定义特性标记了一个条件方法,其执行依赖于指定的预处理标识符。它会引起方法调用的条件编译,取决于指定的值,比如 Debug 或 Trace。规定该特性的语法如下:[Conditional( conditionalSymbol )]

        使用Conditional特性,无论是否定义了DEBUG环境变量,Function1()方法也会被编译至程序集中。这种做法看起来也似乎不那么高效,但是其中占用的仅仅是一点点磁盘空间而已。如果没有被调用,Function1()并不会加载到内存中,也不会被JIT编译。在应用多个Conditional特性时,它们之间的组合关系将为"或"(OR)。

    [Conditional("DEBUG"),Conditional("Trace")] static void Function1() { Console.WriteLine("In Function 1."); }

        而若想创建一个使用"与"(AND)关系的构造,就使用#if/#endif吧。。。

    static void Function1() { #if DEBUG && RELEASE   Console.WriteLine("In Function 1."); #endif }
    

       

      (3) Obsolete

          这个预定义特性标记了不应被使用的程序实体。它可以让您通知编译器丢弃某个特定的目标元素。例如,当一个新方法被用在一个类中,但是您仍然想要保持类中的旧方法,您可以通过显示一个应该使用新方法,而不是旧方法的消息,来把它标记为 obsolete(过时的)。规定该特性的语法如下

    [Obsolete(
       message
    )]
    [Obsolete(
       message,//参数 message,是一个字符串,描述项目为什么过时的原因以及该替代使用什么
       iserror//参数 iserror,是一个布尔值。如果该值为 true,编译器应把该项目的使用当作一个错误。默认值是 false(编译器生成一个警告)
    )]
    

      

    using System;
    public class MyClass
    {
       [Obsolete("Don't use OldMethod, use NewMethod instead", true)]
       static void OldMethod()
       { 
          Console.WriteLine("It is the old method");
       }
       static void NewMethod()
       { 
          Console.WriteLine("It is the new method"); 
       }
       public static void Main()
       {
          OldMethod();
       }
    } 
    View Code

      当您尝试编译该程序时,编译器会给出一个错误消息说明:  Don't use OldMethod, use NewMethod instead

    2、自定义特性   

      .Net 框架允许创建自定义特性,用于存储声明性的信息,可在运行时被检索。创建并使用自定义特性包含四个步骤:

    • 声明自定义特性
    • 构建自定义特性
    • 在目标程序元素上应用自定义特性
    • 通过反射访问特性  

       (1)声明自定义特性

        一个新的自定义特性应派生自 System.Attribute 类。例如:    

    // 一个自定义特性 BugFix 被赋给类及其成员
    [AttributeUsage(AttributeTargets.Class |
    AttributeTargets.Constructor |
    AttributeTargets.Field |
    AttributeTargets.Method |
    AttributeTargets.Property,
    AllowMultiple = true)]
    
    public class PersonAttribute : Attribute
    {}   
    View Code

      (2)构建自定义特性

        让我们构建一个名为 PersonAttribute 的自定义特性,该特性将存储调试程序获得的信息。它存储下面的信息:

      •   bug 的代码编号
      •   辨认该 bug 的开发人员名字
      •   最后一次审查该代码的日期
      •   一个存储了开发人员标记的字符串消息

        我们的 PersonAttribute 类将带有三个用于存储前三个信息的私有属性(property)和一个用于存储消息的公有属性(property)。所以 bug 编号、开发人员名字和审查日期将是 DeBugInfo 类的必需的定位( positional)参数,消息将是一个可选的命名(named)参数。

        每个特性必须至少有一个构造函数。必需的定位( positional)参数应通过构造函数传递。下面的代码演示了 PersonAttribute 类:

    // 一个自定义特性 BugFix 被赋给类及其成员
    [AttributeUsage(AttributeTargets.Class |
    AttributeTargets.Constructor |
    AttributeTargets.Field |
    AttributeTargets.Method |
    AttributeTargets.Property,
    AllowMultiple = true)]
    
    public class PersonAttribute : System.Attribute
    {
      private int bugNo;
      private string developer;
      private string lastReview;
      public string message;
    
      public PersonAttribute (int bg, string dev, string d)
      {
          this.bugNo = bg;
          this.developer = dev;
          this.lastReview = d;
      }
    
      public int BugNo
      {
          get
          {
              return bugNo;
          }
      }
      public string Developer
      {
          get
          {
              return developer;
          }
      }
      public string LastReview
      {
          get
          {
              return lastReview;
          }
      }
      public string Message
      {
          get
          {
              return message;
          }
          set
          {
              message = value;
          }
      }
    }   
    View Code

     

      (3)应用自定义特性

        通过把特性放置在紧接着它的目标之前,来应用该特性:

    [PersonAttribute (45, "Zara Ali", "12/8/2012", Message = "Return type mismatch")]
    [PersonAttribute (49, "Nuha Ali", "10/10/2012", Message = "Unused variable")]
    class Rectangle
    {
      // 成员变量
      protected double length;
      protected double width;
      public Rectangle(double l, double w)
      {
          length = l;
          width = w;
      }
      [PersonAttribute (55, "Zara Ali", "19/10/2012",
      Message = "Return type mismatch")]
      public double GetArea()
      {
          return length * width;
      }
      [PersonAttribute (56, "Zara Ali", "19/10/2012")]
      public void Display()
      {
          Console.WriteLine("Length: {0}", length);
          Console.WriteLine("Width: {0}", width);
          Console.WriteLine("Area: {0}", GetArea());
      }
    }   
    View Code
  • 相关阅读:
    170120、java 如何在pdf中生成表格
    170119、100亿数据1万属性数据架构设计
    170118、快速失败Vs安全失败(Java迭代器附示例)
    170117、spring解决乱码
    170116、centos6.4下nginx和ftp搭建图片服务器
    170113、CentOs6.4中安装和配置vsftp简明教程
    linux nginx完全卸载
    DevOps 的技术栈与工具链
    git与pycharm结合使用
    JMeter和JMeterPlugin的下载安装
  • 原文地址:https://www.cnblogs.com/qtiger/p/11176320.html
Copyright © 2011-2022 走看看