1) A Nullable type is the synthesis type of the basic type plus "whether it is a null Indicator. For a type, if you can either assign a value or assign a null reference to it (indicating that there is no value), we can say that this type can be empty. Therefore, an empty type can indicate a value, or a value does not exist. For example, the reference type similar to String is the void type, while the value type similar to Int32 is not the void type. Because the capacity of the value type is sufficient to indicate a value suitable for this type, it cannot be empty. Some people think that if the value of int type variable is 0, it indicates null. This is incorrect. 0 is also its value and does not indicate null. The following code demonstrates static void Main (string [] args) {// int n = null; // when the int type is directly assigned null, the compiler reports the error "cannot convert the Null type to the int type because it is a type that cannot be considered null" int? OneValue = null; // The Nullable type is very similar to the non-Nullable type. The key lies in the modifier "?" after the type. // Int? OneValue = 10; if (oneValue. hasValue) // use the Nullable type HasValue attribute to determine whether there is a value stored {// int nNum = oneValue; // if you try to obtain the oneValue value, the compiler reports an error to the Console. writeLine (oneValue. value);} else {Console. writeLine ("oneValue value is blank! ") ;}} 2) C # overflow check when one integer is converted to another, the process depends on the overflow check context. The checked keyword is used to enable overflow checks for integer arithmetic operations and conversions explicitly, while the unchecked keyword is used to cancel overflow checks for integer arithmetic operations and conversions. ① Enable overflow check: when the value of the operand is within the value range of the target type, the conversion is successful. Otherwise, an exception will be thrown. See the following code for Demonstration: class TypeConvert {static void Main (string [] args) {TypeConvert typeConvert = new TypeConvert (); typeConvert. doSomething ();} public void DoSomething () {// The value of MyInt is 2147483647 try {int MyInt = int. maxValue; byte MyByte = checked (byte) MyInt);} catch (OverflowException) {throw ;}} in the Code, the maximum value of MyInt is 2147483647, after being forcibly converted to the byte type, the checked keyword is used for overflow check because the value range of the byte is 0-255, here, the byte MyByte type cannot accommodate much larger than its capacity. And throw an exception. ② Canceling the overflow check does not check whether the data exceeds the maximum value of the target data type during the type conversion process, which means that the type conversion is always successful. If the value range of the source data type is greater than the value range of the target data type, the excess part will be truncated. If the value range of the source data is smaller than that of the target data type, after conversion, it will be filled with symbols or zero to the same size as the target type. If it is equal to, it will be directly converted to the target type. The instance code is as follows: class TypeConvert {static void Main (string [] args) {TypeConvert typeConvert = new TypeConvert (); typeConvert. doSomething ();} public void DoSomething () {// The value of MyInt is 2147483647 try {int MyInt = int. maxValue; // byte MyByte = unchecked (byte) MyInt; // This write method is the same as the following statement. The difference is that byte MyByte = (byte) MyInt is generated; // No overflow check is used here, and no exception is thrown. However, the conversion result is incorrect. The maximum value of the byte type is 255, which is quite different from the original value.} Catch (OverflowException) {throw ;}}③ typeof operator typeof is a unary operator. syntax for returning any type of typeof OPERATOR: type type = typeof (Type); the sample code is as follows: class Program {static void Main (string [] args) {Type t = typeof (Program); Console. writeLine ("method:"); MethodInfo [] methodInfo = t. getMethods (); // returns all public methods of the Type, foreach (MethodInfo mInfo in methodInfo) {Console. writeLine (mInfo. toString ();} Console. writeLine ("member :"); MemberInfo [] memberInfo = t. getMembers (); // returns all public members of the Type foreach (MemberInfo mInfo in methodInfo) {Console. writeLine (mInfo. toString ();} Console. readKey () ;}} running result: ④ heavy-duty operator overloading of the operator can only be applied to classes or structures. To overload an operator, you can declare a method named operator X and implement it, such as operator + and operator-. The unary and binary operators can both be overloaded. Correspondingly, the overload method includes one or two parameters (class or structure type). The syntax is: // the overload of the unary operator of the public static custom type operator to overload the operator (type) // The operator (type 1, type 2) to be overloaded by the public static user-defined type operator of the binary operator. Note: The overload of all operators is a static method, the following code example must be modified using public: class Program {public int Value {get; set;} static void Main (string [] args) {Program o1 = new Program (); o1.Value = 10; Program o2 = new Program (); o2.Value = 20; Program o3 = o1 + o2; Console. writeLine (o3.Value); Console. readKey () ;}/// <summary> // here, the "add (+)" operator is overloaded for the Program class to add two objects, the overload of operators improves programming convenience /// </summary> /// <param name = "o1"> </param> /// <param name = "o2"> </param> // <returns> </returns> public static Program operator + (Program o1, program o2) {Program o = new Program (); o. value = o1.Value + o2.Value; return o ;}}