Study Attributes in .net
Attributes是一种新的用来描述信息的类型,我们可以用Attributes来定义设计时或者运行时的信息。对于设计时,我们可以提供帮助文件,
文档等信息,对于运行时,我们可以提供类的域,并用XML来描述。我们还可以用Attributes来设计“自描述” 的组件类型。
究竟Attributes在DOTNET中提供了什么好的功能呢?
先看一段代码:
这一段代码是提醒编译器,Old方法已经过时了(ObsoleteAttribute是.net中已经定义了的Attributes),不能再用了,如果 我们在Main中用了Old(),那么就会出现错误。第一个参数是错误的提示。第二个参数如果为true,则会编译不通过,视为错误。如果为false,则为出现警告。
已经看到Attributes的一些功用了吧?这个是用来描述某个类或方法的。--自描述功能。
对于已经在.net Framework中已定义的Attributes,有很多,比如说,我们在main函数之前碰到的那个[STAThread]就是 STATheadAttributes。它的作用是指示应用程序的 COM 线程模型是单线程单元。
还有比较用到的SerializableAttributes,它的作用是指示一个类可以序列化,注意,在实际使用某个Attributes的时候,可以 把Attributes这个后缀去掉,直接用前部就可以了,比如,SerializableAttributes就用[Serializable]。 STATheadAttributes就用[STAThread]等。
并不是Framework中的Attributes就够用了,很多时候,我们可以按我们所需定义所需要的Attributes。定义一个 Attributes,都需要创建一个类并继承自System.Attribute。
这样就创建了一个自定义的Attributes。下面就是使用它:
但是上面这个只能是说明语法,并没有什么作用。
我们来完善它一下,使之可以自写帮助消息:
但是,上面的AnyClass还是不能在我们的类里面起到什么作用。下面介绍一个在Framework中已定义的Attribute,可以用来控制我们定 义的Attributes的使用方式。它就是AttributeUsage,正确的说,它也是一个AttributeUsageAttribute。
( It describes how a custom attribute class can be used.)
AttributeUseage有三个重要的属性,分别是ValidOn, AllowMultiple, Inherited
ValidOn:获取一组值,这组值标识指示的属性可应用到的程序元素。
AllowMultiple: 获取或设置一个布尔值,该值指示能否为一个程序元素指定多个指示属性实例。
Inherited:获取或设置一个布尔值,该值指示指示的属性能否由派生类和重写成员继承。
解释的挺拗口,我也看不太懂,看例子吧:
第一行设置了AttributeUseage的属性,第一个参数VaildOn表示helpAttribute可以对什么来进行修饰,这里可以对类进行修 饰,而如果对方法修饰的话就就会出现错误,如下:
ValidOn有多个可以使用的参数设置,可以用AttributeTarget.All对所有的方法,类,枚举等进行修饰,以下列举了ValidOn可以设置的值:
第二个参数AllowMultiple表示可不可以使用多次,这里false表示只能对HelpAttribute使用一次。下面的代码连使用相同的Help("this is a do-nothing method"),就出现了错误:
最后一个参数,就表示可不可以被继承。
接着看下面的代码:
现在还没讲到查询某个Attributes的功能,但肯定的说,在程序中是可以查询某个Attributes的。
在这里,对于Class1来说,它的HelpAttributes是这样表示:
Help.Description : This is Class1
Help.Version :No Version is defined for this class
对于Class2来说,它应该是这样的:
Help.Description : This is Class2
Help.Version :1.0
对于Class3来说,它应该是这样的:
Help.Description : This is Class3
Help.Version :2.0
下面一个问题,我们想把我们的Attributes安置在整个汇编代码中,如何安置,编译器怎么知道该如何安置在汇编代码中?而不是别的什么类中?如果把 Attributes安置在一个方法的返回值中呢?又如何做到?
对于这个问题,我们需要用到Attributes的指示器,来告诉编译器把这些个Attributes放置在哪儿。
例如:
设置Attribute可以在Run-Time的时候来获取它的值。这样做的一个好处就是能够保持对象或者方法的状态。这也只能这样理解,具体的可能理解不对,需要实际应用多了才知道。
比如我们写入这样的代码:
我们将会在Main的函数中获取AnyMehod的HelpAttribute,看看它是怎么获取的:
首先是获取进程exe或DLL文件名,并且用Assembly去加载它,然后Assembly有GetCustomAttributes的方法,就可以得 到这个进程的属性值。然后把attr强制转化成我们的HelpAttribute类型,并且得到了相应的对象。
这里获得的值应该是:
其实只要把那
Assembly a = Assembly.LoadFrom(assemblyName);
foreach (Attribute attr in a.GetCustomAttributes(true))
改成相应的类适用就可以了,如下:
Type t = typeof(ClassName);
foreach(Attribute attr in t.GetCutomAttributes(true))
代码如下 :
至于具体的讲解文章可以到这个地方查看:http://www.codeproject.com/csharp/attributes.asp
另外,这篇文章的代码放置在:F:\Source\shipfi\MyTestCode\CSConsole\使用属性\UseAttribute
究竟Attributes在DOTNET中提供了什么好的功能呢?
使用Framework中的Attributes
先看一段代码:
using System;
public class AnyClass
{
[Obsolete("Don't use Old method, use New method", true)]
static void Old( ) { }
static void New( ) { }
public static void Main( )
{
Old( );
}
}
public class AnyClass
{
[Obsolete("Don't use Old method, use New method", true)]
static void Old( ) { }
static void New( ) { }
public static void Main( )
{
Old( );
}
}
这一段代码是提醒编译器,Old方法已经过时了(ObsoleteAttribute是.net中已经定义了的Attributes),不能再用了,如果 我们在Main中用了Old(),那么就会出现错误。第一个参数是错误的提示。第二个参数如果为true,则会编译不通过,视为错误。如果为false,则为出现警告。
已经看到Attributes的一些功用了吧?这个是用来描述某个类或方法的。--自描述功能。
对于已经在.net Framework中已定义的Attributes,有很多,比如说,我们在main函数之前碰到的那个[STAThread]就是 STATheadAttributes。它的作用是指示应用程序的 COM 线程模型是单线程单元。
还有比较用到的SerializableAttributes,它的作用是指示一个类可以序列化,注意,在实际使用某个Attributes的时候,可以 把Attributes这个后缀去掉,直接用前部就可以了,比如,SerializableAttributes就用[Serializable]。 STATheadAttributes就用[STAThread]等。
自定义Attributes
并不是Framework中的Attributes就够用了,很多时候,我们可以按我们所需定义所需要的Attributes。定义一个 Attributes,都需要创建一个类并继承自System.Attribute。
using System;
public class HelpAttribute : Attribute
{
}
public class HelpAttribute : Attribute
{
}
这样就创建了一个自定义的Attributes。下面就是使用它:
[Help()]
public class AnyClass
{
}
public class AnyClass
{
}
但是上面这个只能是说明语法,并没有什么作用。
我们来完善它一下,使之可以自写帮助消息:
public class HelpAttribute : Attribute
{
public HelpAttribute(String Descrition_in)
{
this.description = Description_in;
}
protected String description;
public String Description
{
get
{
return this.description;
}
}
}
[Help("this is a do-nothing class")]
public class AnyClass
{
}
{
public HelpAttribute(String Descrition_in)
{
this.description = Description_in;
}
protected String description;
public String Description
{
get
{
return this.description;
}
}
}
[Help("this is a do-nothing class")]
public class AnyClass
{
}
但是,上面的AnyClass还是不能在我们的类里面起到什么作用。下面介绍一个在Framework中已定义的Attribute,可以用来控制我们定 义的Attributes的使用方式。它就是AttributeUsage,正确的说,它也是一个AttributeUsageAttribute。
使用AttributeUsage
( It describes how a custom attribute class can be used.)
AttributeUseage有三个重要的属性,分别是ValidOn, AllowMultiple, Inherited
ValidOn:获取一组值,这组值标识指示的属性可应用到的程序元素。
AllowMultiple: 获取或设置一个布尔值,该值指示能否为一个程序元素指定多个指示属性实例。
Inherited:获取或设置一个布尔值,该值指示指示的属性能否由派生类和重写成员继承。
解释的挺拗口,我也看不太懂,看例子吧:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false )]
public class HelpAttribute : Attribute
{
public HelpAttribute(String Description_in)
{
this.description = Description_in;
}
protected String description;
public String Description
{
get
{
return this.description;
}
}
}
public class HelpAttribute : Attribute
{
public HelpAttribute(String Description_in)
{
this.description = Description_in;
}
protected String description;
public String Description
{
get
{
return this.description;
}
}
}
第一行设置了AttributeUseage的属性,第一个参数VaildOn表示helpAttribute可以对什么来进行修饰,这里可以对类进行修 饰,而如果对方法修饰的话就就会出现错误,如下:
[Help("this is a do-nothing class")]
public class AnyClass //正确,可以对类进行修饰。
{
[Help("this is a do-nothing method")] //错误,对方法不能修饰。
public void AnyMethod()
{
}
}
public class AnyClass //正确,可以对类进行修饰。
{
[Help("this is a do-nothing method")] //错误,对方法不能修饰。
public void AnyMethod()
{
}
}
ValidOn有多个可以使用的参数设置,可以用AttributeTarget.All对所有的方法,类,枚举等进行修饰,以下列举了ValidOn可以设置的值:
Assembly,
Module,
Class,
Struct,
Enum,
Constructor,
Method,
Property,
Field,
Event,
Interface,
Parameter,
Delegate,
All = Assembly | Module | Class | Struct | Enum | Constructor | Method | Property | Field | Event | Interface | Parameter | Delegate,
ClassMembers = Class | Struct | Enum | Constructor | Method | Property | Field | Event | Delegate | Interface )
第二个参数AllowMultiple表示可不可以使用多次,这里false表示只能对HelpAttribute使用一次。下面的代码连使用相同的Help("this is a do-nothing method"),就出现了错误:
[Help("this is a do-nothing class")]
[Help("it contains a do-nothing method")]
public class AnyClass
{
[Help("this is a do-nothing method")] //错误,这句前面已经使用一次了。
public void AnyMethod()
{
}
}
[Help("it contains a do-nothing method")]
public class AnyClass
{
[Help("this is a do-nothing method")] //错误,这句前面已经使用一次了。
public void AnyMethod()
{
}
}
最后一个参数,就表示可不可以被继承。
接着看下面的代码:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false,
Inherited = false)]
public class HelpAttribute : Attribute
{
public HelpAttribute(String Description_in)
{
this.description = Description_in;
this.verion = "No Version is defined for this class";
}
protected String description;
public String Description
{
get
{
return this.description;
}
set
{
this.description = value;
}
}
protected String version;
public String Version
{
get
{
return this.version;
}
//if we ever want our attribute user to set this property,
//we must specify set method for it
set
{
this.verion = value;
}
}
}
[Help("This is Class1")]
public class Class1
{
}
[Help("This is Class2", Version = "1.0")]
public class Class2
{
}
[Help("This is Class3", Version = "2.0",
Description = "This is do-nothing class")]
public class Class3
{
}
Inherited = false)]
public class HelpAttribute : Attribute
{
public HelpAttribute(String Description_in)
{
this.description = Description_in;
this.verion = "No Version is defined for this class";
}
protected String description;
public String Description
{
get
{
return this.description;
}
set
{
this.description = value;
}
}
protected String version;
public String Version
{
get
{
return this.version;
}
//if we ever want our attribute user to set this property,
//we must specify set method for it
set
{
this.verion = value;
}
}
}
[Help("This is Class1")]
public class Class1
{
}
[Help("This is Class2", Version = "1.0")]
public class Class2
{
}
[Help("This is Class3", Version = "2.0",
Description = "This is do-nothing class")]
public class Class3
{
}
现在还没讲到查询某个Attributes的功能,但肯定的说,在程序中是可以查询某个Attributes的。
在这里,对于Class1来说,它的HelpAttributes是这样表示:
Help.Description : This is Class1
Help.Version :No Version is defined for this class
对于Class2来说,它应该是这样的:
Help.Description : This is Class2
Help.Version :1.0
对于Class3来说,它应该是这样的:
Help.Description : This is Class3
Help.Version :2.0
下面一个问题,我们想把我们的Attributes安置在整个汇编代码中,如何安置,编译器怎么知道该如何安置在汇编代码中?而不是别的什么类中?如果把 Attributes安置在一个方法的返回值中呢?又如何做到?
对于这个问题,我们需要用到Attributes的指示器,来告诉编译器把这些个Attributes放置在哪儿。
例如:
[assembly: Help("this a do-nothing assembly")]
就是告诉编译器把Attributes放置在汇编IL中。
书上有段话,我把它摘入在这儿吧: The assembly identifier before the Help attribute explicitly tells the compiler that this attribute is attached to entire assembly.
The possible identifiers are
* assembly
* module
* type
* method
* property
* event
* field
* param
* return
The possible identifiers are
* assembly
* module
* type
* method
* property
* event
* field
* param
* return
在运行时查找某个Attribute
设置Attribute可以在Run-Time的时候来获取它的值。这样做的一个好处就是能够保持对象或者方法的状态。这也只能这样理解,具体的可能理解不对,需要实际应用多了才知道。
比如我们写入这样的代码:
[assembly : Help("This Assembly demonstrates custom attributes
creation and their run-time query.")]
//our custom attribute class
public class HelpAttribute : Attribute
{
public HelpAttribute(String Description_in)
{
//
// TODO: Add constructor logic here
this.description = Description_in;
//
}
protected String description;
public String Description
{
get
{
return this.deescription;
}
}
}
//attaching Help attribute to our AnyClass
[HelpString("This is a do-nothing Class.")]
public class AnyClass
{
//attaching Help attribute to our AnyMethod
[Help("This is a do-nothing Method.")]
public void AnyMethod()
{
}
//attaching Help attribute to our AnyInt Field
[Help("This is any Integer.")]
public int AnyInt;
}
class QueryApp
{
public static void Main()
{
}
}
creation and their run-time query.")]
//our custom attribute class
public class HelpAttribute : Attribute
{
public HelpAttribute(String Description_in)
{
//
// TODO: Add constructor logic here
this.description = Description_in;
//
}
protected String description;
public String Description
{
get
{
return this.deescription;
}
}
}
//attaching Help attribute to our AnyClass
[HelpString("This is a do-nothing Class.")]
public class AnyClass
{
//attaching Help attribute to our AnyMethod
[Help("This is a do-nothing Method.")]
public void AnyMethod()
{
}
//attaching Help attribute to our AnyInt Field
[Help("This is any Integer.")]
public int AnyInt;
}
class QueryApp
{
public static void Main()
{
}
}
我们将会在Main的函数中获取AnyMehod的HelpAttribute,看看它是怎么获取的:
public static void Main()
{
HelpAttribute HelpAttr;
//Querying Assembly Attributes
String assemblyName;
Process p = Process.GetCurrentProcess();
assemblyName = p.ProcessName + ".exe";
Assembly a = Assembly.LoadFrom(assemblyName);
foreach (Attribute attr in a.GetCustomAttributes(true))
{
HelpAttr = attr as HelpAttribute;
if (null != HelpAttr)
{
Console.WriteLine("Description of {0}:\n{1}",
assemblyName,HelpAttr.Description);
}
}
}
{
HelpAttribute HelpAttr;
//Querying Assembly Attributes
String assemblyName;
Process p = Process.GetCurrentProcess();
assemblyName = p.ProcessName + ".exe";
Assembly a = Assembly.LoadFrom(assemblyName);
foreach (Attribute attr in a.GetCustomAttributes(true))
{
HelpAttr = attr as HelpAttribute;
if (null != HelpAttr)
{
Console.WriteLine("Description of {0}:\n{1}",
assemblyName,HelpAttr.Description);
}
}
}
首先是获取进程exe或DLL文件名,并且用Assembly去加载它,然后Assembly有GetCustomAttributes的方法,就可以得 到这个进程的属性值。然后把attr强制转化成我们的HelpAttribute类型,并且得到了相应的对象。
这里获得的值应该是:
Description of QueryAttribute.exe:
This Assembly demonstrates custom attributes creation and their run-time query.
以上是获取Assembly中的Attribute。如果要获取Class,Method中的Attribute呢?其实只要把那
Assembly a = Assembly.LoadFrom(assemblyName);
foreach (Attribute attr in a.GetCustomAttributes(true))
改成相应的类适用就可以了,如下:
Type t = typeof(ClassName);
foreach(Attribute attr in t.GetCutomAttributes(true))
代码如下 :
Type t = typeof(Class2);
foreach(Attribute attri in t.GetCustomAttributes(true))
{
helpAttr = attri as HelpAttribute;
if(null != helpAttr)
{
Console.WriteLine("Description of {0}:\n{1}",
t.FullName,helpAttr.HelpString);
}
}
Console.ReadLine();
foreach(Attribute attri in t.GetCustomAttributes(true))
{
helpAttr = attri as HelpAttribute;
if(null != helpAttr)
{
Console.WriteLine("Description of {0}:\n{1}",
t.FullName,helpAttr.HelpString);
}
}
Console.ReadLine();
至于具体的讲解文章可以到这个地方查看:http://www.codeproject.com/csharp/attributes.asp
另外,这篇文章的代码放置在:F:\Source\shipfi\MyTestCode\CSConsole\使用属性\UseAttribute