C# - Method Attribute and Reflection

简介:
在C#中,许多地方都用到了特征属性Attribute,它可以用来描述类型或方法,从而赋予它们一些额外的功能或特性。事实上,当你打开Visual Studio并创建一个Windows Forms Application应用程序时,在默认的Program.cs文件中,Main函数就被标记上了特征属性。
[STAThread]
static   void  Main()
{
}
  特征属性是一组继承自Attribute的类,通常被用来修饰类型或方法,在类型或方法定义之前以方括号括起来。如我们可以给类的属性添加特征属性使其可以被序列化为XML:
复制代码
public   class  Movie
{
  [XmlElement(
" MovieName " )]
  
public   string  Title
  { 
get set ; }

  [XmlElement(
" MovieRating " )]
  
public   float  Rating
  { 
get set ; }

  [XmlElement(
" MovieReleaseDate " )]
  
public  DateTime ReleaseDate
  { 
get set ; }
}
复制代码
  如同上面的代码片段,特征属性允许接收参数,这要取决于你使用了什么样的特征属性类型。当然,在.NET中我们也可以自定义特征属性类,但前提是自定义类必须继承自Attribute类。下面是一个例子:
复制代码
class  MyToken : Attribute
{
  
public   string  DisplayName {  get set ; }

  
public  MyToken( string  dn)
  { DisplayName 
=  dn; }
}
复制代码
  然后,我们在代码中使用上面我们自定义的特征属性类:
复制代码
public   static   class  Operations
{
  [MyToken(
" Operation 1 " )]
  
public   static   void  Operation1()
  {
    System.Windows.Forms.MessageBox.Show(
" Hey, I'm operation 1! " );
  }

  [MyToken(
" Operation 2 " )]
  
public   static   void  Operation2()
  {
    System.Windows.Forms.MessageBox.Show(
" Hey, I'm operation 2! " );     
  }
}
复制代码
  那么我们在方法前使用我们自定义的特征属性有什么意义呢?来看看一个实际的例子,我们通过反射来找出所有被标记成我们自定义的特征属性的方法。
复制代码
using  System;
using  System.Collections.Generic;
using  System.ComponentModel;
using  System.Data;
using  System.Drawing;
using  System.Linq;
using  System.Text;
using  System.Windows.Forms;
using  System.Reflection;

namespace  WindowsFormsApplication1
{
    
public   partial   class  Form1 : Form
    {
        
public  Form1()
        {
            InitializeComponent();
            PopulateComBox();
        }

        
private   void  PopulateComBox()
        {
            MethodInfo[] methods 
=   typeof (Operations).GetMethods();

            MyToken token 
=   null ;
            List
< KeyValuePair < String, MethodInfo >>  items  =   new  List < KeyValuePair < string , MethodInfo >> ();

            
foreach  (MethodInfo method  in  methods)
            {
                token 
=  Attribute.GetCustomAttribute(method,  typeof (MyToken),  false as  MyToken;
                
if  (token  ==   null )
                {
                    
continue ;
                }

                items.Add(
new  KeyValuePair < String, MethodInfo > (token.DisplayName, method));
            }

            
this .comboBox1.DataSource  =  items;
            
this .comboBox1.DisplayMember  =   " Key " ;
            
this .comboBox1.ValueMember  =   " Value " ;
        }

        
private   void  button1_Click( object  sender, EventArgs e)
        {
            
if  ( this .comboBox1.SelectedIndex  <   0 )
            {
                
return ;
            }

            MethodInfo method 
=   this .comboBox1.SelectedValue  as  MethodInfo;
            
if  (method  !=   null )
            {
                method.Invoke(
null null );
            }
        }
    }

    
public   class  MyToken : Attribute
    {
        
public   string  DisplayName {  get set ; }

        
public  MyToken( string  dn)
        { DisplayName 
=  dn; }
    }

    
public   static   class  Operations
    {
        [Obsolete]
        
public   static   void  Operation0()
        {
            System.Windows.Forms.MessageBox.Show(
" Hey, I'm operation 0! " );
        }

        [MyToken(
" Operation 1 " )]
        
public   static   void  Operation1()
        {
            System.Windows.Forms.MessageBox.Show(
" Hey, I'm operation 1! " );
        }

        [MyToken(
" Operation 2 " )]
        
public   static   void  Operation2()
        {
            System.Windows.Forms.MessageBox.Show(
" Hey, I'm operation 2! " );
        }

        
public   static   void  Operation3()
        {
            System.Windows.Forms.MessageBox.Show(
" Hey, I'm operation 3! " );
        }
    }
}
复制代码

  上面是一个WinForm程序的完整代码,窗体上一共两个控件,一个Combox,一个Button。程序启动时调用PopulateComBox()方法,通过反射找出Operations类中所有被标记为MyToken特征属性的方法,添加到集合List中。这里有两个地方需要说明一下:

  1. 通过Attribute.GetCustomAttribute()方法尝试找到MethodInfo[]数组中所有被标记为MyToken特征属性的方法。注意GetCustomAttribute()方法的参数形式。typeof(Operations).GetMethods()用来返回类型Operations中所有public访问级别的方法。

  2. 集合items被定义为List泛型类型,该List泛型类型被指定为具有名值对的形式。实际上你也可以使用任何具有名值对的集合类型,如Hashtable。

  当点击按钮的时候,程序通过ComBox.SelectedValue属性找到当前选中的方法名称,然后使用Invoke()方法执行它,下面是程序执行时的效果截图。

 

 

  你应该注意到了在ComBox中只有两项:Operation1和Operation2。但是我们看到Operations类中一共有四个被定义为public访问级别的static方法,为什么反射只找到了两个方法呢?这是因为我们在反射中规定只找出被定义为MyToken特征属性的方法,方法Operation0被定义为特征属性Obsolete(该特征属性用于标识方法已过期并不再使用,你应该在一些早期.NET版本中发布的类型或方法中见过这个标识,或者在代码的智能提示中见过它)而非MyToken,方法Operation3不包含有特征属性。
  反射的最大好处就是可以动态地加载程序集,并获取程序集中的类型,以及类型中的属性和方法,并执行它们。在上例中,如果你想添加一个新的Operation方法并让它在ComBox中出现且能被执行,你只需要做一件事情,那就是在Operations类中增加一个方法并标注为MyToken特征属性,同时加上一些你期待执行的代码。

本文转自Jaxu博客园博客,原文链接:http://www.cnblogs.com/jaxu/archive/2011/08/15/2139137.html,如需转载请自行联系原作者

相关文章
|
C#
艾伟:C# Design Patterns (1) - Factory Method
Simple Factory Pattern (简单工厂模式) 特性: 把类的实例化工作,集中到一个「工厂类」去处理,亦即将 new instance 的工作,都交给一个「工厂」去处理,而不要分散写在各个类中。
860 0
|
C#
艾伟_转载:C# Design Patterns (1) - Factory Method
Simple Factory Pattern (简单工厂模式) 特性: 把类的实例化工作,集中到一个「工厂类」去处理,亦即将 new instance 的工作,都交给一个「工厂」去处理,而不要分散写在各个类中。
942 0
|
算法 C# Java
使用C# (.NET Core) 实现模板方法模式 (Template Method Pattern)
本文的概念内容来自深入浅出设计模式一书. 项目需求 有一家咖啡店, 供应咖啡和茶, 它们的工序如下: 咖啡: 茶: 可以看到咖啡和茶的制作工序是差不多的, 都是有4步, 其中有两步它们两个是一样的, 另外两步虽然具体内容不一样, 但是都做做的同一类工作.
1309 0
|
C# 设计模式 .NET
使用C# (.NET Core) 实现简单工厂(Simple Factory) 和工厂方法设计模式 (Factory Method Pattern)
本文源自深入浅出设计模式. 只不过我是使用C#/.NET Core实现的例子.   前言 当你看见new这个关键字的时候, 就应该想到它是具体的实现. 这就是一个具体的类, 为了更灵活, 我们应该使用的是接口(interface).
1401 0
|
关系型数据库 Go C#
C#设计模式之二工厂方法模式(Factory Method Pattern)【创建型】
原文:C#设计模式之二工厂方法模式(Factory Method Pattern)【创建型】 一、引言       在上一篇文章中我们讲解了过渡的一种模式叫做【简单工厂】,也有叫【静态工厂】的,通过对简单工厂模式得了解,我们也发现了它的缺点,就是随着需求的变化我们要不停地修改工厂里面的方法的代码,需求变化越多,里面的If--Else--也越多,这样就会造成简单工厂的实现逻辑过于复杂。
1541 0