Study Attributes in .net

        Attributes是一种新的用来描述信息的类型,我们可以用Attributes来定义设计时或者运行时的信息。对于设计时,我们可以提供帮助文件, 文档等信息,对于运行时,我们可以提供类的域,并用XML来描述。我们还可以用Attributes来设计“自描述” 的组件类型。

       究竟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( );
    }
}

      这一段代码是提醒编译器,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
{
}

       这样就创建了一个自定义的Attributes。下面就是使用它:
[Help()]
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
{
}


       但是,上面的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;
        }            
    }    
}

        第一行设置了AttributeUseage的属性,第一个参数VaildOn表示helpAttribute可以对什么来进行修饰,这里可以对类进行修 饰,而如果对方法修饰的话就就会出现错误,如下:
[Help("this is a do-nothing class")]
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()
    {
    }
}

       最后一个参数,就表示可不可以被继承。


       接着看下面的代码:
[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
{
}


       现在还没讲到查询某个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


在运行时查找某个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()
    {
    }
}

    我们将会在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);
            }
        }
}

       首先是获取进程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();

       至于具体的讲解文章可以到这个地方查看:http://www.codeproject.com/csharp/attributes.asp
       另外,这篇文章的代码放置在:F:\Source\shipfi\MyTestCode\CSConsole\使用属性\UseAttribute
posted @ 2005-09-22 10:01  shipfi  阅读(474)  评论(0编辑  收藏