特性(Attribute)是一种将自定义信息添加到代码元素(程序集、类型、成员、返回值、参数和泛型类型参数)的扩展机制。
特性是通过直接或者间接继承抽象类System.Attribute的方式定义的。
如果要将一个特性附加到一个代码元素中,那么就需要在该代码元素之前用方括号指定特性的类型名称。
- using NPOI.SS.Formula.Functions;
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Linq;
- using System.Reflection;
- using System.Text;
-
- namespace ConsoleApp1
- {
- class Program
- {
- static void Main(string[] args)
- {
-
- }
-
- }
- //所有特性类型都以Attribute结尾。C#能够识别这个后缀并允许在为成员附加特性时忽略该后缀
- //ObsoleteAttribute 适用于除程序集、模块、参数和返回值之外的所有程序元素。 将元素标记为已过时通知用户,在产品的未来版本中可能会删除该元素。
- [ObsoleteAttribute]
- public class Foo
- {
- }
- }
特性可以包含参数。
特性参数分为两类:位置参数和命名参数。第一个参数是位置参数,第二个参数是命名参数。位置参数对应于特性类型的公有构造器的参数;命名参数则对应于该特性类型的公有字段或者公有属性。
当指定一个特性时,必须包含对应特性构造器中的位置参数,而命名参数则是可选的。
CLSCompliantAttribute 类:指示程序元素是否符合公共语言规范 (CLS)。 此类不能被继承。
该 CLSCompliantAttribute 属性用于指示特定程序元素是否符合公共语言规范 (CLS) ,后者定义面向 .NET 的任何语言必须支持的功能。
解答:
通过在程序集中声明[assembly: CLSCompliant(true)]特性即可保证整个程序集代码必须遵守CLS,否则编译时将报错。如果程序集代码中某些元素(如属性)需要逃避符合 CLS的检查,可添加[property: CLSCompliant(false)]特性注释。
分析:
CLS 即公共语言规范,它保证了整个应用程序可以无缝跨越.NET 的各种语言。例如C#中的多个相同字母组合的标识符可以通过字母大小写不同区分,但是VB.NET则视为非法,C#的这种做法则被称为没有遵守 CLS。在程序集中声明[CLSCompliant]特性即可保证编译时检查程序集代码是否遵守CLS,以利于其他.NET语言的调用。
- //可声明整个程序集必须遵守CLS
- [assembly: CLSCompliant(true)]
- //可声明被注释的属性可以不遵守CLS,即可正常通过编译
- [property: CLSCompliant(false)]
- //可声明被注释的方法可以不遵守CLS,即可正常通过编译
- [method: CLSCompliant(false)]
只需在类或成员前面注释[Obsolete]特性,一旦主程序中使用了该类或成员,可以在编译时给出警告。
分析:
[Obsolete]特性在团队合作时非常有用,它可以帮助程序员选择性地使用某些调试中的类或方法。[Obsolete]特性的编写方法如以下代码所示:
- [Obsolete("警告文本")]
- 被注释项(一般为类或成员)
- [Obsolete]特性的参数为string类型,即可作为在编译时警告的说明文本。
自定义特性需定义一个System.Attribute类的派生类,才可以在程序中使用。
- using System;
- namespace ConsoleApp1
- {
- class Program
- {
- static void Main(string[] args)
- {
- var bc = new BaseClass();
- Console.WriteLine(bc.BaseField);
- var dc = new DerivedClass();
- BaseClass[] bca = new BaseClass[] { dc, bc };
- foreach (var v in bca)
- {
- Console.WriteLine("object type:{0}", v.GetType().Name);
- var fi = v.GetType().GetFields();
- Console.WriteLine($"IsDefined:{v.GetType().Name}:{v.GetType().IsDefined(typeof(ReviewCommentAttribute), false)}");
- foreach (var f in fi)
- {
- Console.WriteLine("Field:{0}", f.Name);
-
- }
- }
-
- var t = dc.GetType();
- var Attrs = t.GetCustomAttributes(true);
- foreach (var attr in Attrs)
- {
- var attr1 = attr as ReviewCommentAttribute;
- Console.WriteLine($"{attr1.IsValid()}");
- }
- }
- }
- //特性也可被限制使用范围,只需在自定义特性类前面添加[AttributeUsage]特性
- //[AttributeUsage(AttributeTargets.Class | AttributeTargets.Field,AllowMultiple =true,Inherited = false)]
- //该特性第1个参数为 AttributeTargets 枚举值,以上代码为自定义特性仅允许用于类(Class)和字段(Field)。
- //第2个参数AllowMultiple代表在相同元素上是否可以注释多次。第3个参数代表是否可被派生类继承。
- [AttributeUsage(AttributeTargets.Class| AttributeTargets.Field)]
- public sealed class ReviewCommentAttribute : System.Attribute
- {
- public string Description { get; set; }
- public string VersionNumber { get; set; }
- public string ReviewerID { get; set; }
- public ReviewCommentAttribute(string desc, string ver)
- {
- Description = desc;
- VersionNumber = ver;
- }
- public bool IsValid()
- {
- if (ReviewerID.GetType().Name.Equals("String"))
- {
- return true;
- }
- return false;
- }
- }
- class BaseClass
- {
- [ReviewCommentAttribute("","", ReviewerID="111")]
- public int BaseField = 0;
- }
- [ReviewComment("This is Derived", "0.8.1", ReviewerID="111")]
- class DerivedClass : BaseClass
- {
- public int DerivedField = 0;
- }
-
- }
分析:
特性实际是System.Attribute类的派生类,所以自定义特性需要定义以System.Attribute类为基类的特性类,如以下代码所示:
- using System.;
- public class 自定义特性类名称 : Attribute
- {
- 类体代码;
- }