asp.net ashx處理程式中switch case的替代方案總結

willingtolove發表於2019-08-01

在開發 asp.net 專案中,通常使用一般處理程式(ashx)處理前端傳送過來的請求,因為一個handler會處理多個請求,故ajax請求中一般都會加一個action的引數,在handler里根據這個action做相應的處理或返回相應的資料,這裡大多數人都會想到用switch...case做判斷,一開始我也是用的switch,但漸漸地發現,每個case不像一個程式碼塊,不能為其中的變數提供一個獨立的作用域!而且,如果case的情況比較多的話,程式碼看上去也比較臃腫難維護;
那如何替換掉switch...case呢,我想到了如下兩個方案:

1、用委託字典代替switch...case;

首先在handler裡宣告一個私有的靜態委託字典,key為action字串,value為Func委託;然後把action和對應的方法新增到字典中即可;
完整示例程式碼:

namespace WebApplication1
{

    public class Handler1 : IHttpHandler
    {
        static Dictionary<string, Action<HttpContext>> MapActions = new Dictionary<string, Action<HttpContext>>(StringComparer.OrdinalIgnoreCase)
        {
            {"Add", Add},
            {"Sub", Sub}
        };

        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "text/plain";
            try
            {
                var action = context.Request["Action"];
                if (string.IsNullOrEmpty(action))
                {
                    context.Response.StatusCode = (int) HttpStatusCode.BadRequest;
                }

                if (MapActions.ContainsKey(action))
                {
                    var actionFun = MapActions[action];
                    if (actionFun != null)
                    {
                        actionFun(context);
                        //或
                        //actionFun.Invoke(context);
                    }
                    else
                    {
                        context.Response.StatusCode = (int) HttpStatusCode.NotImplemented;
                    }
                }
                else
                {
                    context.Response.StatusCode = (int) HttpStatusCode.NotFound;
                }
            }
            catch (Exception e)
            {
                context.Response.StatusCode = (int) HttpStatusCode.InternalServerError;
            }
            finally
            {
                context.Response.End();
            }
        }

        public static void Add(HttpContext context)
        {
            int num1 = int.Parse(context.Request["Num1"]);
            int num2 = int.Parse(context.Request["Num2"]);
            int result = num1 + num2;
            context.Response.Write(result);
        }

        public static void Sub(HttpContext context)
        {
            int num1 = int.Parse(context.Request["Num1"]);
            int num2 = int.Parse(context.Request["Num2"]);
            int result = num1 - num2;
            context.Response.Write(result);
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

2、利用反射替代switch...case;

利用反射,將action的值與具體的方法對應上;
完整示例程式碼:

namespace WebApplication1
{

    public class Handler2 : IHttpHandler
    {
        static readonly Type[] SearchParamType = new[] { typeof(HttpContext) };
        public void ProcessRequest(HttpContext context)
        {
            var result = ActionInvoke(context);

            context.Response.ContentType = "text/plain";
            context.Response.Write(result);
        }
        private object ActionInvoke(HttpContext ctx)
        {
            var actionFun = this.GetType().GetMethod("ProcessAction_" + ctx.Request["action"] ?? "",
                BindingFlags.NonPublic |
                BindingFlags.IgnoreCase |
                BindingFlags.Instance |
                BindingFlags.Public,
                null,
                SearchParamType,
                null);
            if (null == actionFun)
            {
                return "UnknowAction";
            }
            return actionFun.Invoke(this, new[] { ctx });
        }
        public int ProcessAction_Add(HttpContext context)
        {
            int num1 = int.Parse(context.Request["Num1"]);
            int num2 = int.Parse(context.Request["Num2"]);
            int result = num1 + num2;
            return result;
        }

        public int ProcessAction_Sub(HttpContext context)
        {
            int num1 = int.Parse(context.Request["Num1"]);
            int num2 = int.Parse(context.Request["Num2"]);
            int result = num1 - num2;
            return result;
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

3、比較兩種方案

反射會造成一定的效能損耗;所以使用委託字典方案更加靠譜;

4、其他方案

可以使用設計模式實現,比如工廠模式,狀態模式,中介模式等,但用在上述這個場景,那麼就有殺雞用牛刀的 感覺了;

5、說明

在簡單的邏輯中,case分支少,很少擴充套件,那麼應該用switch語句,因為簡單明瞭,易於閱讀。
如果在複雜的邏輯中,複雜而且混亂的case,而且經常擴充套件什麼的,就應該用委託和反射,使用快取機制。

6、參考

重構:switch語句改成策略模式還是狀態模式:https://blog.csdn.net/qq_21381465/article/details/51298808
中介模式: https://www.cnblogs.com/insus/p/4134383.html


相關文章