一直以来都没理解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,从而获取有价值的信息。