zoukankan      html  css  js  c++  java
  • asp.net ashx处理程序中switch case的替代方案总结


    在开发 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


  • 相关阅读:
    省市区多级联动数据组合
    常用字符串函数
    设计模式分类
    计算机网络学习笔记(绪论第一部分)
    关于JAVA核心技术(卷一)读后的思考(继承中的类、子类和超类)
    关于JAVA核心技术(卷一)读后的思考(用户自定义类,静态域和静态方法的思考以及方法参数)
    关于JAVA核心技术(卷一)读后的思考(对象与类,日历的构造)
    微型学生信息管理系统的建立
    PHP异常处理(Exception)
    使用trait中相同方法的优先级问题
  • 原文地址:https://www.cnblogs.com/willingtolove/p/11285680.html
Copyright © 2011-2022 走看看