157 suggestions for writing high-quality code to improve C # programs [correct string operations, use default transformation methods, but do not treat forced conversions with as and is],
Preface
This document describes the first three suggestions.
1. Correct string operations
Suggestion 2. Use the default Transformation Method
Suggestion 3. differentiate between forced conversion and as and is
There are a lot of things to understand, some of which may not be well understood.
1. Correct string operations
The string should be the most frequently used basic data type in all programming languages. If you are careful with the use, we will pay for the extra performance overhead caused by a string operation. This article will discuss how to avoid such performance overhead from two aspects:
1. Ensure as few packing as possible
2. Avoid allocating additional memory space
First, let's introduce the first aspect. See the following two lines of code:
String str1="str1"+9;String str2="str2"+9.ToString();
From the IL code, we can know that the first line of code completes the packing behavior at runtime, while the second line of code does not carry out the packing behavior, it actually calls the integer ToString () method, which is more efficient than packing. Therefore, when using other value reference types to convert and splice strings, you should avoid using the operator "+", instead of using the ToString () method provided by the value reference type.
Second, avoid allocating additional memory space. For CLR, A string object is a special object, which cannot be changed once assigned a value. Call System. any method in the String class or any operation (such as "=" assignment, "+" concatenation) will create a new String object in the memory, this also means to allocate new memory space for the new object. The following code brings additional runtime overhead.
Private static void NewMethod1 () {string s1 = "abc"; s1 = "123" + s1 + "456 "; /// the above two lines of code create three string object objects and execute a string. contact Method} private static void NewMethod2 () {string re = 9 + "456"; // This method is packed once and called once. contact Method}
You can view the http://www.cnblogs.com/aehyok/p/3504449.html of my previous article about packing and unpacking
The following code does not concatenate strings at runtime, but directly generates a string during compilation.
Private static void NewMethod3 () {string re2 = "123" + "abc" + "456"; // The code is equivalent to // string re2 = "123abc456 ";} private static void NewMethod4 () {const string a = "t"; string re = "abc" + a; // because a is a constant, therefore, this code is equivalent to string = re = "abc" + "t"; eventually equivalent to string re = "abct ";}
Because the use of the System. String class will bring significant performance loss in some cases, Microsoft also provides a StringBuilder type to make up for the shortcomings of the String.
StringBuilder does not re-create a string object. Its Efficiency Comes from allocating memory in an unmanaged way in advance. If StringBuilder does not define the length first, the allocated length is 16 by default. When the StringBuilder string length is less than or equal to 16, StringBuilder will not re-allocate the memory. When the StringBuilder string length is greater than 16 and less than 32, StringBuilder will re-allocate the memory to make it a multiple of 16. In the code above, if the length of the pre-determined string is greater than 16, you can set a more appropriate length for it (such as 32 ). When the StringBuilder re-allocates the memory, it is allocated according to the previous doubling of capacity. Of course, we need to note that the length specified by StringBuilder must be too small. memory needs to be allocated frequently, which is too large and a waste of space.
Check the following code to compare the following two String concatenation methods, which is more efficient:
private static void NewMethod1() { string a = "t"; a += "e"; a += "s"; a += "t"; } private static void NewMethod2() { string a = "t"; string b = "e"; string c = "s"; string d = "t"; string result = a + b + c + d; }
The results show that the efficiency of both is not high. Do not think that the former is less than the string object created by the latter. In fact, the two create the same string object, and the former performs a string three times. the Contact method is called twice more than the latter.
To complete such String concatenation during running (Note: It is runtime), The StringBuilder type is better. The Code is as follows:
Public static void NewMethod () {// defines four variables: string a = "t"; string B = "e"; string c = "s "; string d = "t"; StringBuilder sb = new StringBuilder (a); sb. append (B); sb. append (c); sb. append (d); // The prompt is running, so the following code is not used // StringBuilder sb = new StringBuilder ("t"); // sb. append ("e"); // sb. append ("s"); // sb. append ("t"); // string result = sb. toString ();}
Microsoft also provides another method to simplify this operation, that is, using the string. Format method. The string. Format method uses StringBuilder internally to Format strings. The Code is as follows:
public static void NewMethod4() { string a = "t"; string b = "e"; string c = "s"; string d = "t"; string result = string.Format("{0}{1}{2}{3}", a, b, c, d); }
For a brief introduction to String and StringBuilder, refer to my previous article http://www.cnblogs.com/aehyok/p/3505000.html.
Suggestion 2. Use the default Transformation Method
1. Using the type conversion operator is actually using the internal method (that is, the function) of the type ).There are two types of conversion operators: implicit conversion and explicit conversion (forced conversion ). Conversion operators are generally provided for primitive types.
The so-called "primitive type" refers to the data type directly supported by the compiler. Primitive types include sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, bool, decimal, object, and string.
Int I = 0; float j = 0; j = I; // There is an implicit conversion from int to float I = (int) j; /// an explicit conversion must exist between float and int.
The user-defined type can also provide this type of conversion by reloading the conversion OPERATOR:
Public class Ip {IPAddress value; public Ip (string ip) {value = IPAddress. parse (ip) ;}// overload conversion operator. The implicit keyword is used to declare implicit User-Defined conversion operators. Public static implicit operator Ip (string ip) {Ip iptemp = new Ip (ip); return iptemp;} // rewrite ToString method public override string ToString () {return value. toString () ;}} class Program {public static void Main (string [] args) {Ip ip = "192.168.1.1"; // use the overload conversion operator of the Ip class, implement implicit conversion from string to Ip type Console. writeLine (ip. toString (); Console. readLine ();}}
Provides implicit conversion between string and type Ip addresses.
2. Use built-in Parse and TryParse, or methods such as ToString, ToDouble, and ToDateTime.
For example, to convert from string to int, because it often occurs, int itself provides the Parse and TryParse methods. Generally, if you want to convert a type, we recommend that you first read the API documentation of this type.
3. Use the methods provided by the help class
You can use the System. Convert class and System. BitConverter class for type conversion.
System. Convert provides methods to Convert a primitive type to another primitive type, such as ToChar and ToBoolean. It is worth noting that System. Convert also supports converting any custom type to any primitive type, as long as the custom type inherits the IConvertible interface. For example, in the IP class above, If you convert an Ip address to a string, you can also implement the IConvertible ToString () method in addition to rewriting the ToString method of the Object.
The inherited IConvertible interface must implement other transformation methods at the same time, such as ToBoolean and ToByte. If such transformation is not supported, an InvalidCastException should be thrown instead of a NotImplementedException.
4. Transformation supported by CLR
The transformation supported by CLR, that is, the latter and the latter. This concept is first proposed in Java, which is actually the mutual conversion between the base class and the subclass.
For example, the action Animal class, the Dog class inherit the Animal class, and the Cat class also inherit the Amimal class. Implicit conversions are supported during subclass-to-base class transformation. For example, Dog is obviously an Animal. When Animal is transformed to Dog, it must be an explicit conversion, because Animal may also be a Cat.
Animal animal = new Animal (); Dog dog = new Dog (); animal = dog; // implicit conversion, because Dog is Animal // dog = animal; //// the compilation does not pass dog = (dog) animal; // an explicit conversion is required
Suggestion 3. differentiate between forced conversion and as and is
First, let's look at a simple example.
FirstType firstType = new FirstType(); SecondType secondType = new SecondType(); secondType = (SecondType)firstType;
From the above three lines of code, we can see that the above should be forced conversion.
First, we need to clarify that forced conversion may mean two different things:
1. FirstType and SecondType depend on each other to convert the two types.
2. FirstType is the base class of SecondType.
If forced conversion exists between types, the relationship between them is either the first type or the second type. It is impossible to inherit the relationship at the same time, and provide a transformation symbol.
For the first scenario:
Public class FirstType {public string Name {get; set ;}} public class SecondType {public string Name {get; set;} public static explicit operator SecondType (FirstType firstType) {SecondType secondType = new SecondType () {Name = "transformed from:" + firstType. name}; return secondType;} class Program {static void Main (string [] args) {FirstType firstType = new FirstType () {Name = "First Type "}; secondType secondType = (SecondType) firstType; // secondType = firstType as SecondType. readLine ();}}
Annotations are also added here. Forced conversion can be successful, but compilation fails when the as operator is used.
Here is the result of processing through the conversion operator.
Next, we will add a method in the Program class.
Static void DoWithSomeType (object obj) {// The Compiler first determines whether there is an inheritance relationship between SeondType and ojbect. /// In C #, all types are inherited from objects, so there is no problem in compiling here. /// But the compiler will automatically generate code to check whether the obj is SecondType at runtime. This bypasses the operation conversion character and causes the conversion to fail. SecondType secondType = (SecondType) obj ;}
As mentioned in the comment, errors are reported during compilation.
If all types are traced back to a common base class, the Conversion Based on this base class (that is, the transformation of the base class to the subclass itself ),Use. For the conversion between subclass and subclass, the conversion operator should be provided for forced conversion.
You can rewrite the preceding method
static void DoWithSomeType(object obj) { SecondType secondType = obj as SecondType; }
Ensure that no errors are reported during compilation and execution. The as operator will never throw an exception. If the type does not match (the runtime type of the converted object is neither the target type nor its derived type ), or if the source object for transformation is null, the value after transformation is also null. The DoWithSomeType method before the transformation will cause efficiency problems due to exceptions. After using the as method, this problem can be avoided perfectly.
Now let's look at the second case, that is, FirstType is the base class of SecondType. In this case, both forced transformation and the as operator can be used.
public class FirstType { public string Name { get; set; } } public class SecondType : FirstType { } class Program { static void Main(string[] args) { SecondType secondType = new SecondType() { Name="aehyok"}; FirstType firstType = (FirstType)secondType; firstType = secondType as FirstType; Console.ReadLine(); } }
However, even if you can use forced transformation, we recommend that you use as for transformation from the perspective of efficiency.
Next let's take a look.Is Operator.
static void DoWithSomeType(object obj) { if (obj is SecondType) { SecondType secondType = obj as SecondType; } }
The efficiency of this version is obviously not as high as that of the previous version. Because the current version performs two type checks. However, there is a problem with the as operator, that is, it cannot operate on primitive types. If an algorithm of the primitive type is involved, it is necessary to use is to judge and then perform the transformation operation to avoid the transformation failure.