50 suggestions for improving C # programming (6-10)

Source: Internet
Author: User

6. Different Equal Methods
C # provides the following four methods to determine whether two objects are equal:
1. static bool ReferenceEquals (object left, object right );
2. static bool Equals (object left, object right );
3. virtual bool Equals (object right );
4. static bool operator = (MyClass left, MyClass right );
When you implement equal methods of your own classes, we generally rewrite 3rd methods. when determining whether there are equal value types, We will rewrite 4th methods. 1st and 2 methods will never be overwritten.
The equality of objects must satisfy the mathematical equality of several properties: 1. itself is equal to itself. 2. testability, that is, a = B, B = c, then a = c. 3. Symmetry, that is, a = B, then B =.
The first method, ReferenceEquals, returns True when two variables point to the same object; otherwise, False.
This method only compares object identifiers rather than object content. Therefore, when this method is applied to a value-type variable, False is always returned. -- (because at this time, different objects will be generated for each value type variable for the packing operation.) At the same time, this method is the most efficient, because it only compares object identifiers.
The implementation of Equals in the second method is the same as the following code:
Public static new bool Equals (object left, object right)
{
// Check object identity
If (Object. ReferenceEquals (left, right ))
Return true;
// Both null references handled abve
If (Object. ReferenceEquals (left, null) |
Object. ReferenceEquals (right, null ))
Return false;
Return left. Equals (right );
}
Note that the System. ValueType method does not overwrite the methods 1 and 2, and only the 3rd methods are overwritten. Therefore, we do not recommend to override the custom value type. (The custom value type will also overwrite 4th methods =)
However, the rewritten Equals method is worse, because it needs to compare all member variables without knowing the specific types of these Members, so here it uses the reflection technology, as we all know, reflection of value types is performance-consuming (there are packing and unpacking operations ). Therefore, when defining our own value type, we should rewrite the Equals method to improve efficiency.
For the reference type, try to use the predefined equality method. When you override Equals (), you also need to implement IEquatable Interface, because the generic interface is not implemented, there will be a type conversion problem, the conversion of the derived class to the base class may be normal, that is, the derived class Object = base class object, however, the base class cannot be converted to a derived class, so the base class object is not equal to the object of the derived class, which violates the equality in the mathematical sense. Therefore, we should implement IEquatable Interface Method to convert both the base class and the derived class to the interface object, so that they can convert each other and then determine whether they are equal.
The = method is not recommended for custom reference types.


7. GetHashCode () trap
GetHashCode () is used only in one place: the Hash value is defined for the Key in the Hash-based set, usually in the HashSet And Dictionary Container.
GetHashCode () has many problems. For the reference type, it is inefficient; For the value type, it is usually incorrect. Therefore, it is not recommended to rewrite this function, and you must be careful when using this function.


8. Preference for query syntax rather than Loop
Compare the following two pieces of code:
Use loops to assign values to arrays and Output
Int [] foo = new int [100];
For (int num = 0; num <foo. Length; num ++)
Foo [num] = num * num;
Foreach (int I in foo)
Console. WriteLine (I. ToString ());
Use the query syntax (LINQ) value assignment and Lambda expression to output
Int [] foo = (from n in Enumerable. Range (0,100)
Select n * n). ToArray ();
Foo. ForAll (n) => Console. WriteLine (n. ToString ()));
Where ForAll is in the List Here we need a simple extension:
Public static class Extensions
{
Public static void ForAll (This IEnumerable Sequence, Action Action)
{
Foreach (T item in sequence)
Action (item );
}
}
The complete procedure is as follows:

using System;using System.Diagnostics.Contracts;using System.Collections.Generic;using System.Linq;public static class Extensions{    public static void ForAll
 
  (    this IEnumerable
  
    sequence,    Action
   
     action)    {        foreach (T item in sequence)            action(item);    }}class App{    static void Main()    {        int[] foo = (from n in Enumerable.Range(0, 100)                     select n * n).ToArray();        foo.ForAll((n) => Console.WriteLine(n.ToString()));        Console.ReadKey();    }}
   
  
 


The above is a simple set of array creation and output, it seems that there is no difference between the query syntax and the loop, the following comparison of the two-dimensional array sorting operation:
Create a two-dimensional array in a loop and sort it as follows:
Private static IEnumerable > ProduceIndices ()
{
Var storage = new List > ();
For (int x = 0; x <100; x ++)
For (int y = 0; y <100; y ++)
If (x ++ y <100)
Storage. Add (Tuple. Create (x, y ));
Storage. Sort (point1, point2) =>
(Point2.Item1 * point2.Item1 + point2.Item2 * point2.Item2). CompareTo (
Point1.Item1 * point1.Item1 + point1.Item2 * point1.Item2 ));
Return storage;
}
The query syntax is sorted as follows:
Private static IEnumerable > QueryIndices ()
{
Return from x in Enumerable. Range (0,100)
From y in Enumerable. Range (0,100)
Where x + y <100
Orderby (x * x + y * y) descending
Select Tuple. Create (x, y );
}
Now it is obvious that the query syntax is simple to implement complex sorting operations, while the loop is very lengthy and not readable.


9. Avoid conversion of user-defined types in your API
Custom type conversion: (implicit conversion)
Static public implicit operator Ellipse (Circle c)
{
Return new Ellipse (c. center, c. center,
C. radius, c. radius );
}
In this case, you can implicitly convert a Circle object to an Ellipse object. This implicit conversion is automatic, and then the following method is executed:
Public static void Flatten (Ellipse e)
{
E. R1/= 2;
E. R2 * = 2;
}
// Call it using a circle:
Circle c = new Circle (new PointF (3.0f, 0), 5.0f );
Flatten (c );
At this time, although the program can be converted normally, the generated temporary object (e) is modified to become garbage, but the original object is not modified.
In addition, once an object can be converted to another object, the internal members of each other's objects can be accessed, thus losing the encapsulation of the class.


10. Use optional parameters to reduce method Overloading
A named parameter with the default value is an optional parameter. When calling a method, you can specify only the parameters you need. This is obviously more convenient than multiple overload methods. In fact, if you use four optional parameter methods, 15 different Overloading is required.

Related Article

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.