Introduction
The series "c # extensions and Methods" by hechongtian gave me a lot of inspiration, many of which greatly improved the efficiency of code writing, recently, I have studied the extension methods provided by his article c # extension methods, whimsy, and metamorphosis Article 3: switch/case group extension, I implemented it again according to my habits. Now I want to share my implementation.
Example
Let's take a look at the example in his original article:
I think the only unpleasant part here is the highlighted part, because the type must be explicitly declared and processed in the future. I want the compiler to export the return type directly, let's take a look at the improved implementation:
String typeName = typeId. Switch ()
. CaseReturn (0, "food ")
. CaseReturn (1, "beverage ")
. CaseReturn (2, "liquor ")
. CaseReturn (3, "poison ")
. DefaultReturn ("unknown ")
. ReturnValue;
After a series of CaseReturn/DefaultReturn operations, you can use the ReturnValue attribute to access the final returned results. In this way, you can directly use them without passing in expressions for subsequent processing.
Another benefit is that when the code segment is located in the method body,You can return the result directly.But if you pass in an expression to process the result as in the original text, you cannot directly return the result. In the expression, return is only considered as the return at the expression level.
There is also a code segment like thisIt can be used in method parameters., Which is very convenient and can be regarded as an enhanced version of the ternary expression.
In the original text, there is another overload:
Check the highlighted part. The parameter at this position is only used to adjust the judgment basis. I don't think it is necessary to write it as password. Length. Switch (......) That's it, so I didn't implement it in this overload mode.
The equivalent code written in my implementation mode is:
Private static Color GetBackColor2 (string password)
{
Var r = password. Length. Switch ()
. CaseReturn (f => f <= 4,255)
. CaseReturn (f => f <= 6,192)
. CaseReturn (7,128)
. CaseReturn (8, 64)
. DefaultReturn (0)
. ReturnValue;
Return Color. FromArgb (255,255-r, 255-r );
}
Although the compiler's automatic derivation function can be enjoyed without passing in an operation result processing expression, sometimes the Operation Result Expression is very useful, such as the example in the original article:
Here, we first disable break for all filtering procedures, and then accumulate the returned results in turn using the input expression.
For such an application, a custom expression must be passed in to process the result. In this case, the type must be explicitly declared, and my implementation is similar to this, however, the input expression requires two parameters. The first parameter is the newly obtained return result, and the second parameter is the current return result. The expression is required to return the processed result, it can be substituted into the next processing or used as the final result. The equivalent code is:
Private static int GetReward (int count)
{
Return count. Switch (int n, int o) => n + o)
. CaseReturn (f => f> 5, 1, false)
. CaseReturn (f => f> 10, 10, false)
. CaseReturn (f ==> f> 20,100, false)
. CaseReturn (f => f> 50,100 0, false)
. CaseReturn (f => f> 100,100 0)
. ReturnValue;
}
Some people may wonder why the method names are CaseReturn and DefaultReturn with a Return? Isn't that cool? Is it difficult to name it directly in Case?
This is because I have implemented another form: no return value form
See the following code:
Private void form=formclosing (object sender, FormClosingEventArgs e)
{
If (IsBusy)
MessageBox. Show (@ "the download is in progress. Do you want to close this window and stop the download?
Yes. Close the window and abort the download.
No-only close the window and do not stop the download
Cancel-do not perform any operation "," prompt"
, MessageBoxButtons. YesNoCancel, MessageBoxIcon. Question). Switch ()
. CaseRun (DialogResult. Yes, f => this. Stop ())
. CaseRun (DialogResult. No, f => {})
. DefaultRun (f => e. Cancel = true );
}
This Code uses the CaseRun and DefaultRun methods to execute the passed expression. Its function is to perform different processing based on different dialog box options, which is easy to understand.
The reason for naming CaseRun and CaseReturn differently, rather than Overloading is because CaseReturn also has a overload similar to CaseRun, that is, the second parameter is also an overload of the expression.
Although the overload of CaseReturn requires that the input expression have a return value (Func <T, T>), the second parameter of CaseRun does not require a return value (Action <T> ), however, when a single-sentence Lambda expression is passed in, ambiguity may occur.
For example, a method with a return value is executed in an expression. Because a single Lambda expression does not need to explicitly use the return keyword, the compiler cannot accurately export which overload is to be executed, in this way, the compiler may be crazy, and then it is considered as the most consistent Func <T, T> form overload, and the compiler may just want to execute this method, you do not want to obtain the returned value and report it to the result.
(Scenario example: the method for executing SQL statements on the database is called in a single Lambda expression. This method returns the total number of affected records, the programmer may want to simply execute the SQL statement, but it happens that the returned result of the Switch () method chain is deduced as int type, the program will reload the expression to the form of Func <T, T>, so that the returned value affects the final return result)
Therefore, if there is no different name, when the second parameter uses a single Lambda expression to execute a method with a return value, the program will tend to execute it in the form of Func <T, T>, in this case, the problem may not be possible, but it is annoying and difficult to find out when Ambiguity Determination occurs. Therefore, I want to keep this form of differentiated naming.
Tips
In use, the methods shown above and their overloading can be mixed and used, but pay attention to the following points:
- The Default class method can only be used at the end of the statement chain, but multiple similar methods can be appended.
Specifically, the Case method is not allowed after the Default class method.
- After the Switch (), the type of the returned result is qualitative only when the CaseReturn method is written for the first time. All subsequent CaseReturn methods will follow this type.
Because no type is explicitly declared in the Switch () method, the return type derivation is delayed until the CaseReturn method is written for the first time.
The Switch does not have this delay derivation feature in the form of parameter overload.
- If the CaseReturn method has not been written, after the DefaultRun method is written, the method chain ends, and the subsequent method chain cannot be written or the returned result cannot be obtained.
This design is very natural, because it has no practical significance to write anything later. Here we are prompted that people who are afraid of not knowing it mistakenly think it is a BUG.
Not just replace switch
Because the Switch extension scheme supports the input expression for determination and execution, it can also be used to replace if ...... Else if ...... For example, in the following code, the code at the bottom is equivalent to the commented-out code:
Var str = "test ";
Var on = true;
Var day = DateTime. Today;
// If (str. StartsWith ("t") & on) str = "1 ";
// Else if (str. Length> 9) str = "2 ";
// Else if (str = "none") {str = "3"; on = false ;}
// Else if (day <DateTime. Now) str = "4 ";
// Else on = false;
Str. Switch ()
. CaseRun (f => f. StartsWith ("t") & on, f => str = "1 ")
. CaseRun (f => f. Length> 9, f => str = "2 ")
. CaseRun ("none", f => {str = "3"; on = false ;})
. CaseRun (f => day <DateTime. Now, f => str = "4 ")
. DefaultRun (f => on = false );
Significance of Expansion
What are the advantages of this extension in addition to making the code more complex to bring back the profound knowledge of the author?
The advantage is that it can be used in a single Lambda expression, so that you can be more profound ......
Haha, joke. It's not just a single Lambda expression. When acting as a method parameter and the ternary expression is not enough, this extension will be useful, you can define temporary variables and assign values to them, or create a method to solve such simple discriminant problems.
Its form may not be elegant, but it can make your code structure more elegant, and let you focus on solving the problem at hand, rather than reading and writing in the code page.
Summary
Again, I would like to thank him for bringing us so many inspirations. Let's make full use of the extension methods. This is our self-made syntactic sugar :)
Download
Extension Method source code: http://www.uushare.com/user/icesee/file/2155948
XPS version: http://www.uushare.com/user/icesee/file/2155951 in this article
Source: http://www.cnblogs.com/SkyD/archive/2009/10/26/1589682.html
Read the full text
Category:Net view comments