How is the switch too long in C # optimized? You can use reflection or delegates

Source: Internet
Author: User
Tags foreach reflection switch case

When the code was optimized, the switch case was found to be too long, and some 30 more than a screen would be a poor readability of the code. Especially when we look at the code to pull down the box I personally feel that this is unreasonable. However, I do not recommend that a switch be reflected or delegated to resolve. Look at the actual situation analogy 10 thought is still acceptable. Because the switch looks more direct and the efficiency is relatively best. Let's use code to explain it a little bit.

1: The traditional usage

1.1: Now we have a need to pass parameters to get the relevant information. First, we'll look at the method.

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: Calls from the client


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: Effect


The above is our most conventional usage looks the most intuitive but did you ever think about it if there are 30 ways do you still do the switch case? So I'm going to use the delegate code here.

2: Delegate override switch

I found a problem on the top. Action messy, if too much can not understand what is what is so we add enumeration

2.1: Establishing an enumeration

public enum Actionenum
{
<summary>
Number
</summary>
serialnumber = 0,
<summary>
Name
</summary>
Name = 1,
<summary>
Age
</summary>
Age = 2,
<summary>
Birthday
</summary>
Birthday = 3
}


2.2: I take the dictionary to save all the 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: Establish a delegate (this is relatively simple in fact, in the method can also extract similar operations placed in the delegate execution)


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


2.4: Client Invocation


Console.WriteLine (Exec ("Alldictionary[actionenum.age"));


2.5: Effect


3: Reflection replaces switch

3.1 Create a custom attribute class (for the purpose of attaching the information in the method)


public class Methodattribute:attribute
{
Public Actionenum methodname;

Public Methodattribute (Actionenum methodname)
{
This. methodname = methodname;
}
}


3.2: Define a base class


public class Basemethod
{
Public Hashtable getmethodattribute<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} over range", actionname);
return message;
}
}


3.3: Modify the Switchmethod class and add attributes to the method


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: Client Invocation


string result = new Switchmethod (). Doaction (Actionenum.serialnumber, "1332");


3.5: Notes


3.5.1:type. GetMethods (): Gets all the methods in this class that include the base class

3.5.2:method. GetCustomAttributes (typeof (Methodattribute), false): Gets all custom attributes about Methodattribute type for this method

3.5.3:methodinfo: Represents access to methods in a class

3.6: Operation effect



Three ways of summarizing

1: The traditional usage

Advantages: Simple and easy to read, high efficiency

Disadvantage: Many of the equivalent time will cause a long, difficult to maintain, may modify one of the cases will cause unknown error

2: Commissioned

Advantages: Use the delegate to extract the public, reduce the amount of code

Disadvantage: After adding a dictionary, you need to add a subkey manually after the dictionary. I always feel awkward and I'm a little more efficient.

3: Reflection

Advantages: Less code, not in consideration of how the internal implementation, but also in line with the opening and closing principles, only need to add new methods, other places do not make changes. Strong maintenance

Disadvantage: Obviously this is the least efficient (no caching is included here)


Replace switch with reflection


Call different methods according to the different values passed in


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 + "method not found";
Break

}
Ltrresult.text = result;
}


The following is implemented using the reflection mechanism, which requires a custom attribute class


public class Actionmethodattribute:attribute
{
public string Actiontypename;

Public Actionmethodattribute (String typeName)
{
This. Actiontypename = TypeName;
}
}


Then define a base class


Public abstract class GENERICBLL
{
Public Hashtable getmethodattribute<t> (t)
{
Hashtable ht = new Hashtable ();
Hashtable obj = Cachehandlerif (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}
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;
}
}


Implement class inheritance,


public class REFLECTTEST:GENERICBLL
{
[Actionmethod ("A")]
public string Geta ()
{
Return "a called";
}

[Actionmethod ("B")]
public string Getb ()
{
Return "called B";
}


[Actionmethod ("C")]
public string getc ()
{
Return "C called";
}
}


The specific call

protected void Btn_reflectclick (object sender, EventArgs e)
{
string result = Reflecttest.doaction (Ddlmethod.selectedvalue);
Ltrresult.text = result;
}

The code in ASPX is as follows


Select D will prompt no D method
<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"/>

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.