The basic elements of the Operator programming language, which makes our code more concise and straightforward. However, in order to solve the problem of different types of operands, we have introduced the concept of forced conversion. Let's look at the contents of this chapter first.
1. Operators
Let's take a look at some common operators:
<1> Conditional operators
Its syntax is as follows:
Condition? True_expression:false_expression
When the condition condition is true, it executes the true_expression, otherwise executes the false_expression.
<2> checked and unchecked operators
Use the following syntax:
checked
{
// Code block
}
You can use the checked operator to check if there is an overflow in the tagged code block. Throws a OverflowException exception if an overflow occurs. If we want to prohibit overflow checking, use the unchecked operator.
Note: Unchecked is the default behavior. If it is not explicitly marked as checked, it is unchecked by default.
<3> is operator
The IS operator can check whether an object is compatible with a particular type. For example, we have two objects A and B. If A and B are compatible, then the expression A is B will be true, otherwise it will be false. Compatibility indicates that A and b are of the same type or have derived relationships between them.
<4> as operator
The as operator is used to perform an explicit conversion of a reference type. If it is compatible with the type being converted, the conversion succeeds, otherwise the AS operator returns a null value.
<5> sizeof operator
The sizeof operator can determine the length (in bytes) of a value type in the stack. If you use the sizeof operator for a non-primitive type, you need to put the code in an unsafe block.
<6>typeof operator
The typeof operator can return a specific type of System.Type object. For example, typeof (String) returns a Type object that represents the System.String.
<7> nullable types and operators
Normally nullable types use a unary or two-tuple operator, and as long as one operand is null, the result is null. When you compare a nullable type, the result is false if one of the operands is null. So the opposite is true because one condition is false.
<8> Empty merge operator (??)
Empty merge operator (??) Provides the convenience of converting a nullable type to a non-empty type. Let's take the nullable type of int as an example:
int? a = null;
int b = a ?? 10; // then b is equal to 10
a = 3;
b = a ?? 10; // then b is equal to 3
2. Equality of comparison objects
Depending on the comparison mechanism, we can be divided into comparison of reference types and comparison of value types :
<1> comparing the equality of reference types
System.Object provides 4 ways to compare the equality of objects.
①referenceequals () method
The ReferenceEquals () method is a static method that tests whether two references are the same instance. As a static method, it cannot be overridden.
② virtual Equals () method
The virtual Equals () method, which is the default comparison reference. But because it is a virtual method, we can rewrite it so that it compares objects by value.
③ static Equals () method
The static version of Equals () is consistent with the functionality of the virtual version, the difference: the static version has two parameters and can handle two objects that have a null method. However, if you compare two references, it is equivalent to calling the virtual version of Equals (), which is equivalent to overriding the static Equals () method
④ comparison operator (= =)
Typically reference types use comparison operators (before they are overloaded) as comparison references (except for System.String, because. NET overrides the comparison operator for string).
<2> Equality of comparison value types
When comparing the equality of a value type, it is the same as the reference type: ReferenceEquals () is used to compare references, equals is used to compare values, and for basic type = = is the comparison value, whereas structs need to be overloaded with the = = operator for comparison.
Note: The ReferenceEquals () method is always false when it refers to a value type. Because this method is called, the value type needs to be boxed into the object, so the same reference will not be obtained.
3. Operator Overloading
In many cases, we use operators to represent an expression, which makes our programs more concise and understandable, while the overloading of operators can also improve our development efficiency. Let's say we define a matrix class, Object A, B, C. Suppose we are to express C = a + B, it may be that way to express the words c = Matrix.add (A, b); I believe that through this example, you should all understand the benefits of operator overloading.
Now let's take a look at the syntax of operator overloading:
// The number of parameters in the parameter list, depending on which operator is overloaded
public static [returned type] operator [overloaded operator] (parameter list)
{
// processing
}
Know the overloaded syntax we're here to do the actual combat:
// Let's take the vector class as an example, suppose it has three integer fields x, y, z, and define vector addition.
public static vector operator + (vector lhs, vector rhs)
{
vector ans = new vector ();
ans.x = lhs.x + rhs.x;
ans.y = lhs.y + rhs.y;
ans.z = lhs.z + rhs.z;
return ans;
}
At this point we have completed the overloading of the vector class + operator, and now we can use + to do the addition operation directly. The compiler also automatically completes the overload of + =.
There are also two operators that we cannot overload directly, namely the index operator and the cast operator.
Let's take a look at the overloads of the index operators, with the following syntax:
[Access Attribute] [Return Type] this [int index]
{
get {// Add code that returns the index element}
set {// Set the value of the index element}
}
We now take the Chain List class (LinkedList) as an example: Assume that the LinkedList basic element type is linkedlistnode, and that there is a query (int k) method for returning a reference to the K element and a mod (int k, LinkedListNode Node) method to modify the value of the K element. So we overloaded the index operator as follows:
public LinkedListNode this[int index]
{
get
{
return Query(index);
}
set
{
Mod(index, value);
}
}
We have finished overloading the index operators, and now we can use the subscript directly to access the elements of the collection.
Note: The comparison operator must be a pair of overloads in C #. For the self-increment operator (+ +) or the decrement operator (--) operator, the compiler automatically overloads the predecessor + + (-) as long as the Post + + is overloaded in C #, as well as the self-decrement operator (--).
4. Type casting
In many cases we cannot guarantee that all operands are of the same type, which is what we need to cast. However, coercion is also divided into explicit and implicit casts. Conversions differ between different data types, and casts can be divided into five categories:
<1> predefined type casts
To perform a cast on a predefined data type, we just need to remember one criterion:
Big Data conversion to small data requires an explicit cast (because it is unsafe and may lose data), small data conversions to big data can be explicitly cast or implicitly (because it is always safe).
<2> crating and unpacking
The conversion between value types and reference types is often encountered during the casting process. However, because the value type is on the stack, the reference type is on the managed heap. This is what they need to do to convert each other and take boxes and unboxing.
Boxing (boxing): Create a temporary reference type "box" on the heap and load the value type into the "box".
Unpacking (unboxing): a process contrary to boxing. Change the value type that was previously loaded in the box back to the original.
Note: Boxing (value type conversion to reference type) can be explicitly cast or implicitly convertible. However, the unboxing must be an explicit cast. And when unpacking, you must ensure that the existing value type variable must have sufficient space to store all the bytes of the unboxing value. Otherwise, a InvalidCastException exception will be thrown.
<3> casts between base classes and derived classes
The compiler provides a cast between the base class and the derived class, but in fact the conversion does not make any data transformations on the object. Just changed the reference to the object. Because a base class reference can reference an instance of a derived class. Therefore, you can complete the conversion of the derived class to the base class. If the object referenced by the base class is not an object of a derived class, the conversion of the base class to the derived class will fail and throw an exception.
We use a piece of code to illustrate (MyBase is the base class, Myderived is a derived class of MyBase):
MyBase B1 = new MyDerived (); // Implicit conversion from derived class to base class
MyBase B2 = new MyBase ();
MyDerived D1 = (MyDerived) B1; // Success
MyDerived D2 = (MyDerived) B2 // Throw exception
<4> Custom type Casts
A custom type cast, similar to the overloaded operator. Let's say we want to convert from type A to type B type. Then we define the syntax to cast as follows:
public static [casting method] B (A value)
{
// processing
}
The cast mode is divided into display transformations (explicit) and implicit conversions (implicit).
Here we use an example to understand the custom type casts. We take the previous vector class as an example, assuming that our vector is explicitly cast to double (the square of the modulus length of the calculated vector).
public static explicit double(vector v)
{
return (v.x*v.x + v.y*v.y + v.z*v.z);
}
Let's say we have a vector object test and a double-type Len.
Len = (double) test;//Now we have completed the call to the custom type cast
Note : In the process of continuous conversion, sometimes because of the accuracy of the data type is not enough to cause the loss of precision. Only we can use the Convert.touint16 () method to avoid the loss of precision. But there will be a performance penalty. You can also avoid this problem with high-precision data types.
Of course, we can not always in the actual process and the basic data type conversion, class and class conversion is our daily use of more. The transformation between a class and a class is similar to the conversion of a class to a base data type. The only difference is that there are two restrictions on casting between classes and classes:
① A class has an inheritance derivation from a class, you cannot define casts between types (because there is already a cast between them)
② type casts must be defined internally in either the source data type or the target data type
(This is to prevent a third party from introducing the type cast into the class)
<5> multiple type casts
There is no direct casting in the process of conversion The C # compiler will need to find a way to merge several casts together. For example: We have a Foo class that defines the cast of the foo–> int, and now we have the object of Foo converted to a double type, then the compiler will convert: foo, int, double. However, if you rely on multiple casts, the performance of your program will be insufficient. That is, if we need the conversion of Foo-and double, we define this transformation directly, and performance is more advantageous than multiple conversions.
attached :
1. C # Supported Operators
Group |
Operator |
Primary operator |
() . [] x + + x--new typeof sizeof checked unchecked |
Unary operators |
+ - ! ~ ++x--x Data type coercion |
Multiply/divide operators |
* / % |
Add/Subtract Operators |
+ - |
Shift Operators |
<< >> |
Relational operators |
< > <= >= is as |
Comparison operators |
== != |
Bitwise AND operator |
& |
Bitwise XOR operator |
^ |
Bitwise OR operator |
| |
Boolean AND operator |
&& |
Boolean OR operator |
|| |
Conditional operators |
?: |
Assignment operators |
= + = = *=/=%= &= |= ^= <<= >>= >>>= |
2. Operators that support overloading
Category |
Operator |
Limit |
Arithmetic two-dollar operator |
+ * / - % |
No |
Arithmetic unary operators |
+ - ++ -- |
No |
Bitwise two-dollar operator |
& | ^ << >> |
No |
Bitwise unary Operators |
! ~ True False |
True and false must be overloaded with pairs |
Comparison operators |
= = = >= <= < > |
Comparison operators must be overloaded with pairs |
Assignment operators |
+ = = *=/=%= &= |= ^= <<= >>= |
Do not explicitly overload these operators, which are implicitly overloaded by the compiler |
Index operators |
[] |
The index operator cannot be overloaded directly |
Data type cast operator |
() |
The cast operator cannot be overloaded directly |
C # Advanced Programming, Chapter 7th, operator and type casting--Learning Notes