使用反射分发 switch 操作

类别:.NET开发 点击:0 评论:0 推荐:
今天在网上看到一个很有用的东西,加上我的blog里面什么也没有,所以就拷贝过来装门面。

原文地址:点晴工作室    作者:梁利锋

有时候,我们经常需要处理一些比较大的 switch 语句,如:
public interface IAction
{
  void DoAction(string ActionName);
}
public class OkCancelAction : IAction
{
  public void DoAction(string ActionName)
  {
    switch( ActionName )
    {
      case "OK":
        Console.WriteLine("OK Action raised.");
        break;
      case "CANCEL":
        Console.WriteLine("CANCEL Action raised.");
        break;
      default:
        throw new Exception("ActionName Not Defined.");
    }
  }
}
  一般的,如果这个 switch 比较大,可以使用如下的方法进行分发:
public interface IAction
{
  void DoAction(string ActionName);
}

public class OkCancelAction : IAction
{
  public void DoAction(string ActionName)
  {
    switch( ActionName )
    {
      case "OK":
        Ok_Clicked();
        break;
      case "CANCEL":
        Cancel_Clicked();
        break;
      default:
        throw new Exception("ActionName Not Defined.");
    }
  }

  private void Ok_Clicked()
  {
    Console.WriteLine("OK Action raised.");
  }

  private void Cancel_Clicked()
  {
    Console.WriteLine("CANCEL Action raised.");
  }
}
  不过在使用了反射之后,以上的分发方法还可以进一步封装,以便在写真正的 Action 类的时候非常简单。当然,反射还是和自定义属性结合才能进行更精确的定制:
[AttributeUsage(AttributeTargets.Method)]
public class ActionMethodAttribute : Attribute
{
  public string ActionName;

  public ActionMethodAttribute(string ActionName)
  {
    this.ActionName = ActionName;
  }
}
  另外,定义一个自定义的异常:
public class ActionNameNotDefinedException : Exception
{
  public ActionNameNotDefinedException() : base("行动名未定义") {}
  public ActionNameNotDefinedException(string ErrorMessage) : base(ErrorMessage) {}
}
  然后是最重要的 ActionBase 类:
public abstract class ActionBase
{
  private Hashtable ht = new Hashtable();
  // Hashtable 没有保存顺序特征,所以加入这一个 ArrayList
  private ArrayList al = new ArrayList();

  public string [] GetActionNames()
  {
    return (string[])al.ToArray(typeof(string));
  }

  public ActionBase()
  {
    Console.WriteLine(this.ToString());
    Type t = this.GetType();
    
    foreach ( MethodInfo mi in t.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.NonPublic) )
    {
      ActionMethodAttribute[] mis = (ActionMethodAttribute[])mi.GetCustomAttributes(typeof(ActionMethodAttribute), false);
      if ( mis != null && mis.Length > 0 )
      {
        string ActionName = mis[0].ActionName;
        al.Add( ActionName );
        ht.Add( ActionName, mi );
      }
    }
  }

  public void DoAction(string ActionName)
  {
    if ( ht.Contains( ActionName ) )
    {
      ((MethodInfo)ht[ActionName]).Invoke(this, new object[] {});
    }
    else
    {
      throw new ActionNameNotDefinedException();
    }
  }
}
  然后,定义真正的 Action 类就很简单了:
public class OkCancelAction : ActionBase
{
  [ActionMethod("OK")]
  private void Ok_Clicked()
  {
    Console.WriteLine("OK Action raised.");
  }

  [ActionMethod("CANCEL")]
  private void Cancel_Clicked()
  {
    Console.WriteLine("CANCEL Action raised.");
  }
}
  调用运行如下所示:
class ApplicationEntry
{
  [STAThread]
  static void Main(string[] args)
  {
    Console.WriteLine("/////////////////////////////////////");
    ActionBase a = new OkCancelAction();

    Console.WriteLine("/////////////////////////////////////");
    string [] ss = a.GetActionNames();
    Console.WriteLine( string.Join("\r\n",ss) );

    Console.WriteLine("/////////////////////////////////////");
    foreach ( string s in ss )
    {
      a.DoAction(s);
    }

    Console.WriteLine("/////////////////////////////////////");
    Console.ReadLine();
  }
}
  要注意的是,要编译运行的话,需要加入“System”、“System.Collections”和“System.Reflection”三个命名空间。

本文地址:http://com.8s8s.com/it/it42525.htm