一直以来都没理解attribute是个什么东西,也没怎么用,但是看msdn或者git上源码使用的还是蛮频繁的,今天好好整理了下,写下自己的理解和例子:
attribute主要用来说明代码段的的信息,标志等;可以一种元数据结构,不会影响到代码段的结果。这个代码段可以是class,struct,method,constructor等结构,下面会给出反编译源码说明哪些代码段可以作为目标。
1,.NET内建attribute
[AttributeUsage]
AttributeUsage主要用来限定attribute可以在哪些情况下下使用,下面是AtttributeUsage的多个构造函数中的一个,其他不赘述:
internal AttributeUsageAttribute(AttributeTargets validOn, bool allowMultiple, bool inherited){this.m_attributeTarget = validOn;this.m_allowMultiple = allowMultiple;this.m_inherited = inherited;}
参数说明:
1),AttributeTarges必要的参数,反编译得到attribute的目标:
public enum AttributeTargets{[__DynamicallyInvokable] Assembly = 1,[__DynamicallyInvokable] Module = 2,[__DynamicallyInvokable] Class = 4,[__DynamicallyInvokable] Struct = 8,[__DynamicallyInvokable] Enum = 16, // 0x00000010[__DynamicallyInvokable] Constructor = 32, // 0x00000020[__DynamicallyInvokable] Method = 64, // 0x00000040[__DynamicallyInvokable] Property = 128, // 0x00000080[__DynamicallyInvokable] Field = 256, // 0x00000100[__DynamicallyInvokable] Event = 512, // 0x00000200[__DynamicallyInvokable] Interface = 1024, // 0x00000400[__DynamicallyInvokable] Parameter = 2048, // 0x00000800[__DynamicallyInvokable] Delegate = 4096, // 0x00001000[__DynamicallyInvokable] ReturnValue = 8192, // 0x00002000[__DynamicallyInvokable] GenericParameter = 16384, // 0x00004000[__DynamicallyInvokable] All = GenericParameter | ReturnValue | Delegate | Parameter | Interface | Event | Field | Property | Method | Constructor | Enum | Struct | Class | Module | Assembly, // 0x00007FFF}
2),allowMutiple是bool类型,可选的参数;ture表示可以在同一个代码段多次使用,默认的是false;
3),inherited是bool类型,可选的参数;ture表示在派生类中继承,默认的值false;
[Obsolete]
主要用来指示代码段是废弃的,并通知编译器,编译器将会给出警告或者错误;
用法:[Obsolete(message)] 和[Obsolte(message(string),iserror(bool))]
message:描述代码段废弃的原因,并指出替代者;iserror:当它是true时,编译器报错,默认时false
这里放代码的话看不出来编译错误,上图明显显示错误,并指示应该时NewMethod。
[Conditional]
主要用来定义一个预定义符号,作为编译条件,类似#ifdef的作用,下面例子说明用法:
#define Test
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;namespace Experiments
{class Program{static void Main(string[] args){System.Console.ReadKey();DoWork();}[Conditional("Test")]static void DoWork(){for (int i = 0; i < 100; i++){Console.WriteLine(i);Thread.Sleep(100);}}}
}
当没有定义#define Test,DoWork方法不执行
[CallerMemberName]
可以自动展示调用者的名字,用在INotifyPerprotyChanged例子:
public class MyUIClass : INotifyPropertyChanged{public event PropertyChangedEventHandler PropertyChanged;public void RaisePropertyChanged([CallerMemberName] string propertyName = null){PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));}private string _name;public string Name{get { return _name; }set{if (value != _name){_name = value;RaisePropertyChanged(); // notice that "Name" is not needed here explicitly}}}}
2,自定义attribute
自定义的attribute必须要继承自Attribute基类,其参数按照MSDN解释分为位置参数(positional parameter)和可选的命名参数(named parameter)。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace Experiments
{[AttributeUsage(AttributeTargets.Class|AttributeTargets.Constructor|AttributeTargets.Field|AttributeTargets.Method|AttributeTargets.Property, AllowMultiple = true)]public class DevelopLog:Attribute{//positional parameterprivate string _developer;private string _reviewer;private string _lastModTime;//named parameterprivate string msg; public string Developer { get => _developer; }public string Reviewer { get => _reviewer; }public string LastModTime { get => _lastModTime; }public string Msg { get => msg; set => msg = value; }public DevelopLog(string dev, string rv, string lmt){_developer = dev;_reviewer = rv;_lastModTime = lmt;}}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace Experiments
{[DevelopLog("zhangsan", "boss", "20180807", Msg = "create class")][DevelopLog("lisi", "boss", "20180807", Msg = "add method dowork")]public class Student{private string _name;private string _age;public Student(string n, string a){_name = n;_age = a;}[DevelopLog("zhangsan", "boss", "20180807")]public void EvertyDayDoThing(){}[DevelopLog("zhangsan", "boss", "20180807")]public void MoringDo(){}[DevelopLog("lisi", "boss", "20180808")]public void NoonDo(){}[DevelopLog("zhangsan", "boss", "20180807", Msg="paly game all day and not do homework")]public void PlayGame(){}}
}
然后在实际应用中,我们可以通过reflection来获取上面描述的attribute,从而获取有价值的信息。