一直以來都沒理解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 parameter
private string _developer;
private string _reviewer;
private string _lastModTime;
//named parameter
private 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,從而獲取有價值的信息