特性

什么是特性?

特性(attribute)是一种允许我们向程序的程序集增加元数据的语言结构。它是用于保存程序结构信息的某种特殊类型的类。

将应用了特性的程序结构叫做目标 设计用来获取和使用元数据的程序(对象浏览器)叫做特性的消费者 .NET预定了很多特性,我们也可以声明自定义特性

创建和使用特性

我们在源代码中将特性应用于程序结构; 编译器获取源代码并且从特性产生元数据,然后把元数据放到程序集中; 消费者程序可以获取特性的元数据以及程序中其他组件的元数据。注意,编译器同时生产和消费特性。

关于特性的命名规范,特性名使用Pascal命名法(首字母大写),并且以Attribute后缀结尾,当为目标应用特性时,我们可以不使用后缀。例如对于SerializableAttribute和MyAttributeAttribute这两个特性,我们把他们应用到结构是可以使用Serializable和MyAttribute。

应用特性

先看看如何使用特性。特性的目的是告诉编译器把程序结构的某组元数据嵌入程序集。我们可以通过把特性应用到结构来实现。

1.在结构前放置特性片段来应用特性; 2.特性片段被方括号包围,特性片段包括特性名和特性的参数列表; 3.应用了特性的结构成为特性装饰。

案例1

[Serializable]    //特性
public class MyClass{
    // ...
}

案例2

[MyAttribute("Simple class","Version 3.57")]    //带有参数的特性
public class MyClass{
    //...
}

Obsolete特性->.NET预定义特性

一个程序可能在其生命周期中经历多次发布,而且很可能延续多年。在程序生命周期的后半部分,程序员经常需要编写类似功能的新方法替换老方法。处于多种原因,你可能不再使用哪些调用过时的旧方法的老代码。而只想用新编写的代码调用新方法。旧的方法不能删除,因为有些旧代码也使用的旧方法,那么如何提示程序员使用新代码呢?可以使用Obsolete特性将程序结构标注为过期的,并且在代码编译时,显示有用的警告信息。

class Program{
    [Obsolete("Use method SuperPrintOut")]    //将特性应用到方法
    static void PrintOut(string str){
        Console.WriteLine(str);
    }
    [Obsolete("Use method SuperPrintOut",true)]//这个特性的第二个参数表示是是否应该标记为错误,而不仅仅是警告。
    static void PrintOut(string str){
        Console.WriteLine(str);
    }
    static void Main(string[] args){
        PrintOut("Start of Main");
    }
}

Conditional特性

Conditional特性允许我们包括或取消特定方法的所有调用。为方法声明应用Conditional特性并把编译符作为参数来使用。

定义方法的CIL代码本身总是会包含在程序集中,只是调用代码会被插入或忽略。

using System.Diagnostics;

class Program{
    [Conditional("DoTrace")] 
    static void TraceMessage(string str){
        Console.WriteLine(str);
    }
    static void Main(){
        TraceMessage("Start of Main");
        Console.WriteLine("Doing work in Main.");
        TraceMessage("End of Main");
    }
}

调用者信息特性

调用者信息特性可以访问文件路径,代码行数,调用成员的名称等源代码信息。

这个三个特性名称为CallerFilePath,CallerLineNumber和CallerMemberName

这些特性只能用于方法中的可选参数

using System.Runtime.CompilerServices;

public static void PrintOut(string message,[CallerFilePath] string filename="",[CallerLineNumber]int lineNumber = 0,[CallerMemberName]string callingMember=""){
    Console.WriteLine("Message:"+message);
    Console.WriteLine("Line :"+lineNumber);
    Console.WriteLine("Called from:"+callingMember);
    Console.WriteLine("Message :"+message);
}

DebuggerStepThrough特性

我们在单步调试代码的时候,常常希望调试器不要进入某些方法。我们只想执行该方法,然后继续调试下一行。DebuggerStepThrough特性告诉调试器在执行目标代码时不要进入该方法调试。有些方法小并且毫无疑问是正确的,在调试时对其反复单步调试只能徒增烦恼。要小心使用该特性,不要排除了可能出现bug的代码。

该特性位于System.Diagnostics命名空间下

该特性可用于类,结构,构造方法,方法或访问器

class Program{
    int _x=1;
    int X{
        get{return _x;};
        [DebuggerStepThrough]
        set{
            _x=_x*2;
            _x+=value;
        }
    }
    public int Y{get;set;}
    [DebuggerStepThrough]
    void IncrementFields(){
        X++;
        Y++;
    }
    static void Main(){
        Program p = new Program();
        p.IncrementFields();
        p.X = 5;
        Console.WriteLine("P.X:"+p.X+" p.Y:"+p.Y);
        Console.ReadKey();
    }
}

其他预定义特性

特性 意义
CLSCompliant 声明可公开的成员应该被编译器检查是否符合CLS。兼容的程序集可以被任何.NET兼容的语言使用
Serializable 声明结构可以被序列化
NonSerialized 声明结构不可以被序列化
DLLImport 声明是非托管代码实现的
WebMethod 声明方法应该被作为XML Web服务的一部分暴露
AttributeUsage 声明特性能应用到什么类型的程序结构。将这个特性应用到特性声明上

多个特性

我们可以为单个结构应用多个特性。有下面两种添加方式

//独立的特性片段相互叠在一起
[Serializable]
[MyAttribute("Simple class","Version 3.57")]
//单个特性片段,特性之间使用逗号间隔
[Serializable,MyAttribute("Simple class","Version 3.57")]

特性目标

我们可以将特性应用到字段和属性等程序结构上。我们还可以显示的标注特性,从而将它应用到特殊的目标结构。要使用显示目标,在特性片段的开始处放置目标类型,后面跟冒号。例如,如下的代码用特性装饰方法,并且还把特性应用到返回值上。

[return:MyAttribute("This value ...","Version2.3")]
[method:MyAttribute("Print....","Version 3.6")]
public long ReturnSettings(){
...

c#定义了10个标准的特性目标。

event    field    method    param    property    
return    type    typevar    assembly    module

其中type覆盖了类,结构,委托,枚举和接口。

typevar指定使用泛型结构的类型参数。

全局特性

我们可以通过使用assembly和module目标名称来使用显式目标说明符把特性设置在程序集或模块级别。

程序集级别的特性必须放置在任何命名空间之外,并且通常放置在AssemblyInfo.cs文件中

AssemblyInfo.cs文件通常包含有关公司,产品以及版权信息的元数据。

[assembly: AssemblyTitle("ClassLibrary1")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ClassLibrary1")]
[assembly: AssemblyCopyright("Copyright ©  2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

results matching ""

    No results matching ""