C#中switch太长了怎么优化?可以使用反射或委托

在代码进行优化的时候,发现了switch
case太长,有的竟然长达30个远远超过一屏这样在代码的可读性来说很差。特别在我们看代码的时候要拉下拉框我个人觉得这是不合理的。但是我不建议有
switch就进行反射或委托来解决。看实际的情况比喻10个以为还是可以接受的。因为switch看起来更加的直接而且效率相对来说是最好的。那下面就用代码来一点点进行解释

1:传统的用法

1.1:现在我们有一个需求通过传递参数来获取相关的信息。首先我们先看方法

public class SwitchMethod {        
        public string GetSerialNumber(string serialNumber)
        {
            return serialNumber;
        }

        public string GetName(string name)
        {
            return name;
        }

        public string GetAge(string age)
        {
            return age;
        }

        public string GetBirthday(string birthday)
        {
            return birthday;
        }

    }

1.2:客户端的调用

string action =Console.ReadLine() ;
            var switchMethod=new SwitchMethod();
            switch (action)
            {
                case "serialNumber":
                Console.WriteLine(switchMethod.GetSerialNumber("1234"));    
                    break;
                case "name":
                    Console.WriteLine(switchMethod.GetName("zhangsan"));
                    break;
                case "age":
                    Console.WriteLine(switchMethod.GetAge("21"));
                    break;
                case "birthday":
                    Console.WriteLine(switchMethod.GetBirthday("19960201"));
                    break;
            }

1.3:效果


以上是我们最常规的用法看起来最直观但是你想过没有如果有30个方法呢你还这样进行switch case吗 50,100个呢所以下面我用委托来代码

2:委托替代switch

上面我又发现一个问题action凌乱,如果太多了就搞不清什么是什么了所以我们加入枚举

2.1:建立枚举

public enum ActionEnum
    {
        /// <summary>
        /// 编号
        /// </summary>
        SerialNumber = 0,
        /// <summary>
        /// 姓名
        /// </summary>
        Name = 1,
        /// <summary>
        /// 年龄
        /// </summary>
        Age = 2,
        /// <summary>
        /// 生日
        /// </summary>
        Birthday = 3
    }

2.2:我采取字典把需要switch的都存起来

private static void LoadDictionary()
        {
            if (AllDictionary.Count<=0)
            {
                var switchMethod = new SwitchMethod();
                AllDictionary.Add(ActionEnum.SerialNumber, switchMethod.GetSerialNumber);
                AllDictionary.Add(ActionEnum.Age, switchMethod.GetAge);
                AllDictionary.Add(ActionEnum.Birthday, switchMethod.GetBirthday);
                AllDictionary.Add(ActionEnum.Name, switchMethod.GetName);
            }            
        }

2.3:建立委托(这是比较简单的其实在方法中还可以提取相似的操作放在委托执行)

public static string Exec(string str,Func<string, string> method) {
           return method(str);
      }

2.4:客户端调用


Console.WriteLine(Exec("21", AllDictionary[ActionEnum.Age]));

2.5:效果


3:反射替代switch

3.1建立一个自定义Attribute类(目的是为了附带方法中的信息)

public class MethodAttribute : Attribute
    {
        public ActionEnum MethodName;

        public MethodAttribute(ActionEnum methodName)
        {
            this.MethodName = methodName;
        }
    }

3.2:定义一个基类

public class BaseMethod
    {
        public Hashtable GetMethodAttribute<T>(T t)
        {
            var hashtable = new Hashtable();
            Type type = t.GetType();            
            foreach (MethodInfo method in type.GetMethods())
            {
                var methodArray = (MethodAttribute[]) method.GetCustomAttributes(typeof (MethodAttribute), false);
                foreach (MethodAttribute actionMethodAttribute in methodArray)
                {
                    ActionEnum actionName = actionMethodAttribute.MethodName;
                    hashtable.Add(actionName, method);
                }
            }
            return hashtable;
        }

        
        public string DoAction(ActionEnum actionName,string str) {
            Hashtable ht = GetMethodAttribute(this);
            string message = ht.Contains(actionName)
                ? ((MethodInfo) ht[actionName]).Invoke(this, new object[] {str}).ToString()
                : string.Format("{0} 超过范围", actionName);
            return message;
        }
    }

3.3:修改SwitchMethod类并给方法加上特性

public class SwitchMethod : BaseMethod
    {
        [Method(ActionEnum.SerialNumber)]
        public string GetSerialNumber(string serialNumber)
        {
            return serialNumber;
        }

        [Method(ActionEnum.Name)]
        public string GetName(string name)
        {
            return name;
        }

        [Method(ActionEnum.Age)]
        public string GetAge(string age)
        {
            return age;
        }

        [Method(ActionEnum.Birthday)]
        public string GetBirthday(string birthday)
        {
            return birthday;
        }
    }

3.4:客户端调用


string result = new
SwitchMethod().DoAction(ActionEnum.SerialNumber,"1332");

3.5:注释

3.5.1:type.GetMethods():获取这个类中所有的方法包括基类的方法

3.5.2:method.GetCustomAttributes(typeof (MethodAttribute),
false):获取这个方法所有关于MethodAttribute类型的自定义特性

3.5.3:MethodInfo:表示对类中方法的访问

3.6:运行效果



三种方式总结

1:传统的用法

优点:简单易读,效率高

缺点:当量很多的时候会造成方法很长,不易维护,可能修改其中某一个case会引起未知的错误

2:委托

优点:使用委托将公有的进行提取,减少代码量

缺点:加入字典后每次添加都需要在字典后手动添加一个子项。总是觉得别扭,效率稍微差点

3:反射

优点:代码量减少,不在考虑内部如何实现,而且符合开闭原则,只需要添加新的方法,其他地方不作修改。维护性强

缺点:很明显这个效率最差(此处并未加入缓存)

补充 利用反射代替switch

根据传进来不同的值,调用不同的方法

protected void btn_SwitchClick(object sender, EventArgs e)
{
    string result = "";
    switch (ddlMethod.SelectedValue)
    {
        case "A":
            result = SwitchTest.GetA();
            break;
        case "B":
            result = SwitchTest.GetB();
            break;
        case "C":
            result = SwitchTest.GetC();
            break;
        default:
            result = ddlMethod.SelectedValue + "方法找不到";
            break;

    }
    ltrResult.Text = result;
}

下面利用反射机制实现,首选需要一个自定义属性类

public class ActionMethodAttribute:Attribute
{
    public string ActionTypeName;

    public ActionMethodAttribute(string typeName)
    {
        this.ActionTypeName = typeName;
    }
}

然后定义一个基类

public abstract class GenericBLL
{
    public Hashtable GetMethodAttribute<T>(T t)
    {
        Hashtable ht = new Hashtable();
        Hashtable obj = CacheHandler<Hashtable>.GetCache(t.ToString());
        if (obj == null)
        {
            Type type = t.GetType();
            foreach (MethodInfo mi in type.GetMethods())
            {
                ActionMethodAttribute[] mis = (ActionMethodAttribute[])mi.GetCustomAttributes(typeof(ActionMethodAttribute), false);
                foreach (ActionMethodAttribute actionMethodAttribute in mis)
                {
                    string actionName = actionMethodAttribute.ActionTypeName;
                    ht.Add(actionName, mi);
                }
            }
            CacheHandler<Hashtable>.SetCache(t.ToString(), ht);
        }
        else
        {
            ht = (Hashtable)obj;
        }
        return ht;
    }

    /// <summary>
    /// return message;
    /// </summary>
    /// <param name="actionName"></param>
    /// <returns></returns>
    public string DoAction(string actionName)
    {
        string message;
        Hashtable ht = GetMethodAttribute(this);
        if (ht.Contains(actionName))
        {
            message = ((MethodInfo)ht[actionName]).Invoke(this, new object[] { }).ToString();
        }
        else
        {
            message = string.Format("{0} Not Defined.!", actionName);
            //throw new Exception(errmsg);
        }
        return message;
    }
}

实现类继承,

public class ReflectTest:GenericBLL
{                   
    [ActionMethod("A")]
    public string GetA()
    {
        return "调用的A";
    }

    [ActionMethod("B")]
    public string GetB()
    {
        return "调用的B";
    }

    [ActionMethod("C")]
    public string GetC()
    {
        return "调用的C";
    }
}

具体的调用

protected void btn_ReflectClick(object sender, EventArgs e)
{
    string result = ReflectTest.DoAction(ddlMethod.SelectedValue);
    ltrResult.Text = result;
}

ASPX中的代码如下

选D会提示没有D方法
<asp:DropDownList ID="ddlMethod" runat="server">
    <asp:ListItem Text="A" Value="A">
    </asp:ListItem>
    <asp:ListItem Text="B" Value="B">
    </asp:ListItem>
    <asp:ListItem Text="C" Value="C">
    </asp:ListItem>
    <asp:ListItem Text="D" Value="D">
    </asp:ListItem>
</asp:DropDownList>
<br />
<asp:Button ID="btnInvoke" Text="Switch" OnClick="btn_SwitchClick" runat="server" />
<asp:Button ID="btnInvokeR" Text="Reflect" OnClick="btn_ReflectClick" runat="server" />
<br>
<asp:Literal ID="ltrResult" runat="server" />

时间: 2024-09-08 19:22:59

C#中switch太长了怎么优化?可以使用反射或委托的相关文章

xml-关于TextView中文本太长的问题

问题描述 关于TextView中文本太长的问题 程序中的一个textview,有一段很长的文本.估计是由于这段文本太长,所以把整个布局都影响了.现在需要输入很长的文本,所以应该以多行显示. 我用的是下面的XML: <TextView android:id="@+id/bottomText" android:layout_height="wrap_content" android:textColor="#FFFFFF" android:bac

ListBox中数据太长无法显示不全怎么办?在线等~

问题描述 ListBox中数据太长无法显示不全怎么办?最好有(C#)代码! 解决方案 解决方案二:ListBox1中的某些数据太长了,在ListBox1列表中只能显示前面一部分,后边的看不到了,有什么好办法?是不是有方法能在mouse放上去时,显示该项的全部内容?解决方案三:up解决方案四:是的,在html页面里面该控件上的tooltip属性绑定全部信息.鼠标放上去的时候就能显示了.解决方案五:在html页面里面该控件上的找不到~~~~tooltip属性绑定全部信息.~~~能不能说明白一些呢?解

求教:在C#中执行游标语句时间太长超时,如何解决

问题描述 大概要执行200个循环,执行时间大概是五分钟左右.在页面里执行总是报时间超时.这个应该如何优化,或者说页面发个命令直接后台执行下面这段语句也可以代码见下:DECLARE@FCUSRNUMBERvarchar(50)DECLARE@FDATEVARCHAR(20)SET@FDATE=CONVERT(varchar(20),DATEADD(MM,-1,GETDATE()),23)DECLAREMy_CursorCURSOR--定义游标FOR(selectdistinctFNUMBERfro

mysql优化-急急急!!mysql,查询中ORDER BY A,B,C DESC 太慢,如何优化??

问题描述 急急急!!mysql,查询中ORDER BY A,B,C DESC 太慢,如何优化?? 急急急!!mysql,查询中ORDER BY A,B,C DESC 太慢,如何优化??急急急!!mysql,查询中ORDER BY A,B,C DESC 太慢,如何优化?? 查询50万条数据,慢死了 解决方案 建立A,B,C的联合索引 解决方案二: 在ABC上建立索引 select * from 表 where id between 0 and (select max(id) from 表) ord

字符串supercalifragilisticexpialidocious是因为太长了而不能放在string变量中吗?

问题描述 我是刚学c#的,现在在看c#入门经典这本书!课后练习里有这么一道题:字符串supercalifragilisticexpialidocious是因为太长了而不能放在string变量中吗?为什么?第一感觉就觉得肯定能放!自己也写了程序试过了!但是为什么他会这样子问呢?郁闷死我了!实在想不明白! 解决方案 解决方案二:string随便多大都可以放,可以放一本书的内容吧,只要放得下..解决方案三:书的质量太差,如果这本书是国人编写的,那就很正常,如果是翻译外文书的话,就是翻译上出了问题.解决

ajax请求时间太长,后台返回json,前台无反应。

问题描述 ajax请求时间太长,后台返回json,前台无反应. 1C 由于后台运算会花费较长时间(大概4.5分钟),这个时间一旦较长,再返回Json给页面时页面就没反应了.`` $.ajaxFileUpload({ url : $(this).attr(""action"") secureuri : false formObj : $(this) append_data : { 'datemonth' : datemonthImport } dataType : '

MySQL中insert语句的使用与优化教程_Mysql

MySQL 表中使用 INSERT INTO SQL语句来插入数据. 你可以通过 mysql> 命令提示窗口中向数据表中插入数据,或者通过PHP脚本来插入数据. 语法 以下为向MySQL数据表插入数据通用的 INSERT INTO SQL语法: INSERT INTO table_name ( field1, field2,...fieldN ) VALUES ( value1, value2,...valueN ); 如果数据是字符型,必须使用单引号或者双引号,如:"value"

交互设计经验:设计过程中存在太多的矛盾

文章描述:交互设计经验:设计过程中存在太多的矛盾. 在产品团队中经常听到有人表态:"我们要做简洁的用户界面",同时又有另外一种声音传来:"我们要做功能强大的产品".乍一听,简洁意味着用户界面控件精炼,然而少数的交互方式如何表达各类强大的功能?反之,强大意味着功能丰富强劲,必然拥有错综复杂的联系,如何让其界面保持简洁?两者似乎无法共存,这让我突然想到自相矛盾的故事,楚国商人夸耀自己的矛锐利万分,同时自己的盾又坚固无比, "以子之矛,陷子之盾,何如?"

Win7笔记本电脑开机时间太长了怎么办?

  Win7笔记本电脑开机时间太长了怎么办?        步骤一:需下载安装360安全卫士 1.打开360安全卫士,点击左下角的"优化加速"; 2.点击"开始扫描"(扫描默认选项:开机加速.系统加速.网络加速.硬盘加速); 3.等待扫描完成后点击"立即优化"; 4.优化最后步骤可能会弹出"一键优化提醒"窗口,我们点击窗口中的"全选",然后点击"确认优化". 步骤二: 1.点击开始菜单,