[C#] to replace the switch-case code and long for a more beautiful manner

Recommended for you: Get network issues from WhatsUp Gold. Not end users.

The switch-case statement is a branch of commonly used statements we coding process. However, it also called into the Xiao Hebai Xiao He, whenever we asked a have time to add case new branch of hundreds of thousands of lines of switch-case code segment, we have to code readability and maintainability continuously decreased and headache trouble.

In fact, we can have many ways to avoid this branch of switch-case code section and long, so as to write more beautiful code. In.Net we can simply decomposition switch-case code.


Select a common example: module uses switch-case to process the received Command

If we define the following 10 CommandID now.

 1     /// <summary>
 2     /// Definition of commands.
 3     /// </summary>
 4     enum CommandID
 5     {
 6         Abs = 1,
 7         Sin = 2,
 8         Sinh = 3,
 9         Asin = 4,
10         Tan = 5,
11         Tanh = 6,
12         Atan = 7,
13         Cos = 8,
14         Cosh = 9,
15         Acos = 10
16     }

CommandID

Here we define a CommandHandler1 class to handle these commands. This kind of use switch-case statements are processed by different CommandID. We can each CommandID processing logic encapsulated in each function (several methods assume that the Math defined here is lazy, we package processing logic), and then call the corresponding function can be in each case.

 1     class CommandHandler1
 2     {
 3         /// <summary>
 4         /// Handle the command.
 5         /// </summary>
 6         /// <param name="cmdID">The command ID of the command to be handled.</param>
 7         /// <param name="cmdArg">The command argument of the command to be handled.</param>
 8         /// <returns>The handle result.</returns>
 9         public double HandleCommand(CommandID cmdID, double cmdArg)
10         {
11             double retValue;
12             switch (cmdID)
13             {
14                 case CommandID.Abs:
15                     retValue = Math.Abs(cmdArg);
16                     break;
17                 case CommandID.Sin:
18                     retValue = Math.Sin(cmdArg);
19                     break;
20                 case CommandID.Sinh:
21                     retValue = Math.Sinh(cmdArg);
22                     break;
23                 case CommandID.Asin:
24                     retValue = Math.Asin(cmdArg);
25                     break;
26                 case CommandID.Tan:
27                     retValue = Math.Tan(cmdArg);
28                     break;
29                 case CommandID.Tanh:
30                     retValue = Math.Tanh(cmdArg);
31                     break;
32                 case CommandID.Atan:
33                     retValue = Math.Atan(cmdArg);
34                     break;
35                 case CommandID.Cos:
36                     retValue = Math.Cos(cmdArg);
37                     break;
38                 case CommandID.Cosh:
39                     retValue = Math.Cosh(cmdArg);
40                     break;
41                 case CommandID.Acos:
42                     retValue = Math.Acos(cmdArg);
43                     break;
44                 default:
45                     retValue = this.HandleDefaultCommand(cmdArg);
46                     break;
47             }
48 
49             return retValue;
50         }
51 
52         /// <summary>
53         /// Handle the default command.
54         /// </summary>
55         /// <param name="cmdArg">The command argument of the default command.</param>
56         /// <returns>The handle result.</returns>
57         private double HandleDefaultCommand(double cmdArg)
58         {
59             return 0;
60         }
61     }

CommandHandler1

In CommandHandler1, if we add a command, you need to add a new command method, modification of HandleCommand method body at the same time, add a case branch and call the new method.


The following code dictionary and commissioned by switch-case CommandHandler1. We defined a new class of CommandHandler2, commissioned by the method that will handle each CommandID is stored in a dictionary table (cmdHandlers), in HandleCommand the method body, found through the cmdID delegate methods corresponding to process the response cmdID.

 1     class CommandHandler2
 2     {
 3         /// <summary>
 4         /// The dictionary contains all the command handlers to handle the commands.
 5         /// </summary>
 6         private Dictionary<CommandID, Func<double, double>> cmdHandlers = new Dictionary<CommandID, Func<double, double>>
 7         {
 8             {CommandID.Abs, Math.Abs}, {CommandID.Sin, Math.Sin}, {CommandID.Sinh, Math.Sinh}, {CommandID.Asin, Math.Asin},
 9             {CommandID.Tan, Math.Tan}, {CommandID.Tanh, Math.Tanh}, {CommandID.Atan, Math.Atan}, {CommandID.Cos, Math.Cos},
10             {CommandID.Cosh, Math.Cosh}, {CommandID.Acos, Math.Acos}
11         };
12 
13         /// <summary>
14         /// Handle the command.
15         /// </summary>
16         /// <param name="cmdID">The command ID of the command to be handled.</param>
17         /// <param name="cmdArg">The command argument of the command to be handled.</param>
18         /// <returns>The handle result.</returns>
19         public double HandleCommand(CommandID cmdID, double cmdArg)
20         {
21             var cmdHandler = this.cmdHandlers.ContainsKey(cmdID) ? this.cmdHandlers[cmdID] : this.HandleDefaultCommand;
22             return cmdHandler(cmdArg);
23         }
24 
25         /// <summary>
26         /// Handle the default command.
27         /// </summary>
28         /// <param name="cmdArg">The command argument of the default command.</param>
29         /// <returns>The handle result.</returns>
30         private double HandleDefaultCommand(double cmdArg)
31         {
32             return 0;
33         }
34     }

CommandHandler2

When we add a command, only need to add a new command method, at the same time will be entrusted to the new command method and its corresponding added to the dictionary in the table can be.


Here we look at the performance of these two methods. In the test performance, we will CMD all of the processing methods have been replaced with HandleDefaultCommand.

  1     class CommandHandlerTest1
  2     {
  3         /// <summary>
  4         /// Handle the command.
  5         /// </summary>
  6         /// <param name="cmdID">The command ID of the command to be handled.</param>
  7         /// <param name="cmdArg">The command argument of the command to be handled.</param>
  8         /// <returns>The handle result.</returns>
  9         public double HandleCommand(CommandID cmdID, double cmdArg)
 10         {
 11             double retValue;
 12             switch (cmdID)
 13             {
 14                 case CommandID.Abs:
 15                     retValue = this.HandleDefaultCommand(cmdArg);
 16                     //retValue = Math.Abs(cmdArg);
 17                     break;
 18                 case CommandID.Sin:
 19                     retValue = this.HandleDefaultCommand(cmdArg);
 20                     //retValue = Math.Sin(cmdArg);
 21                     break;
 22                 case CommandID.Sinh:
 23                     retValue = this.HandleDefaultCommand(cmdArg);
 24                     //retValue = Math.Sinh(cmdArg);
 25                     break;
 26                 case CommandID.Asin:
 27                     retValue = this.HandleDefaultCommand(cmdArg);
 28                     //retValue = Math.Asin(cmdArg);
 29                     break;
 30                 case CommandID.Tan:
 31                     retValue = this.HandleDefaultCommand(cmdArg);
 32                     //retValue = Math.Tan(cmdArg);
 33                     break;
 34                 case CommandID.Tanh:
 35                     retValue = this.HandleDefaultCommand(cmdArg);
 36                     //retValue = Math.Tanh(cmdArg);
 37                     break;
 38                 case CommandID.Atan:
 39                     retValue = this.HandleDefaultCommand(cmdArg);
 40                     //retValue = Math.Atan(cmdArg);
 41                     break;
 42                 case CommandID.Cos:
 43                     retValue = this.HandleDefaultCommand(cmdArg);
 44                     //retValue = Math.Cos(cmdArg);
 45                     break;
 46                 case CommandID.Cosh:
 47                     retValue = this.HandleDefaultCommand(cmdArg);
 48                     //retValue = Math.Cosh(cmdArg);
 49                     break;
 50                 case CommandID.Acos:
 51                     retValue = this.HandleDefaultCommand(cmdArg);
 52                     //retValue = Math.Acos(cmdArg);
 53                     break;
 54                 default:
 55                     retValue = this.HandleDefaultCommand(cmdArg);
 56                     break;
 57             }
 58 
 59             return retValue;
 60         }
 61 
 62         /// <summary>
 63         /// Handle the default command.
 64         /// </summary>
 65         /// <param name="cmdArg">The command argument of the default command.</param>
 66         /// <returns>The handle result.</returns>
 67         private double HandleDefaultCommand(double cmdArg)
 68         {
 69             return 0;
 70         }
 71     }
 72 
 73     class CommandHandlerTest2
 74     {
 75         /// <summary>
 76         /// The dictionary contains all the command handlers to handle the commands.
 77         /// </summary>
 78         //private Dictionary<CommandID, Func<double, double>> cmdHandlers = new Dictionary<CommandID, Func<double, double>>
 79         //{
 80         //    {CommandID.Abs, Math.Abs}, {CommandID.Sin, Math.Sin}, {CommandID.Sinh, Math.Sinh}, {CommandID.Asin, Math.Asin},
 81         //    {CommandID.Tan, Math.Tan}, {CommandID.Tanh, Math.Tanh}, {CommandID.Atan, Math.Atan}, {CommandID.Cos, Math.Cos},
 82         //    {CommandID.Cosh, Math.Cosh}, {CommandID.Acos, Math.Acos}
 83         //};
 84         private Dictionary<CommandID, Func<double, double>> cmdHandlers;
 85 
 86         public CommandHandlerTest2()
 87         {
 88             cmdHandlers = new Dictionary<CommandID, Func<double, double>>
 89             {
 90                 {CommandID.Abs, this.HandleDefaultCommand}, {CommandID.Sin, this.HandleDefaultCommand},
 91                 {CommandID.Sinh, this.HandleDefaultCommand}, {CommandID.Asin, this.HandleDefaultCommand},
 92                 {CommandID.Tan, this.HandleDefaultCommand}, {CommandID.Tanh, this.HandleDefaultCommand},
 93                 {CommandID.Atan, this.HandleDefaultCommand}, {CommandID.Cos, this.HandleDefaultCommand},
 94                 {CommandID.Cosh, this.HandleDefaultCommand}, {CommandID.Acos, this.HandleDefaultCommand}
 95             };
 96         }
 97 
 98         /// <summary>
 99         /// Handle the command.
100         /// </summary>
101         /// <param name="cmdID">The command ID of the command to be handled.</param>
102         /// <param name="cmdArg">The command argument of the command to be handled.</param>
103         /// <returns>The handle result.</returns>
104         public double HandleCommand(CommandID cmdID, double cmdArg)
105         {
106             var cmdHandler = this.cmdHandlers.ContainsKey(cmdID) ? this.cmdHandlers[cmdID] : this.HandleDefaultCommand;
107             return cmdHandler(cmdArg);
108         }
109 
110         /// <summary>
111         /// Handle the default command.
112         /// </summary>
113         /// <param name="cmdArg">The command argument of the default command.</param>
114         /// <returns>The handle result.</returns>
115         private double HandleDefaultCommand(double cmdArg)
116         {
117             return 0;
118         }
119     }
120 
121     class Program
122     {
123         static void Main(string[] args)
124         {
125             List<CommandID> cmdList = new List<CommandID>()
126             {
127                 CommandID.Abs, CommandID.Sin, CommandID.Sinh, CommandID.Asin, CommandID.Tan,
128                 CommandID.Tanh, CommandID.Atan, CommandID.Cos, CommandID.Cosh, CommandID.Acos
129             };
130 
131             Stopwatch watch = new Stopwatch();
132 
133             watch.Start();
134             CommandHandlerTest1 test1 = new CommandHandlerTest1();
135             for (int i = 0; i <1000000; i++)
136             {
137                 for (int j = 0; j <10; j++)
138                 {
139                     test1.HandleCommand(cmdList[j], 0.1);
140                 }
141             }
142 
143             watch.Stop();
144             Console.WriteLine(watch.ElapsedMilliseconds);
145 
146             watch.Reset();
147             watch.Start();
148             CommandHandlerTest2 test2 = new CommandHandlerTest2();
149             for (int i = 0; i <1000000; i++)
150             {
151                 for (int j = 0; j <10; j++)
152                 {
153                     test2.HandleCommand(cmdList[j], 0.1);
154                 }
155             }
156 
157             watch.Stop();
158             Console.WriteLine(watch.ElapsedMilliseconds);
159 
160             Console.ReadLine();
161         }
162     }

Performance Test

Originally thought that the dictionary table method + principal performance should be higher than switch-case, but the test results were disappointing (CommandHandler1 than CommandHandler2 but high nearly 50%). Analysis of the possible reasons for this.:

1 through a scheduling approach than directly call the method efficiency is relatively low,

2 of the switch-case code compiler optimizes.

Fortunately, the general requirements for the performance is not very high, the average 100W time is a few microseconds at zero, and a plurality of long switch-case code section, it is generally accepted. But for the switch-case code section is short, it is not necessary to use second ways to replace the.

Command of course here, for example, a better solution. Because this article is about how to replace switch-case with a more graceful manner, therefore is not described in detail.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download

Posted by Jane at November 18, 2013 - 4:40 PM