In the process of learning C #, the first thing we encounter is the type. Most of the students think it is very simple and then pass. But let's look back at it, there are still many problems in the type that need our attention. This series of articles is based on "CLR via C #", with some blogs written by others, as well as my own experiences and insights. I hope they can be written from a simple perspective, I will give a thorough explanation of the type issues that need to be noted, so that I can learn more during my blog writing process. Let's start the first section. This section is the most basic problem of the type. It may be very familiar to everyone, but these are the basis of the type and need to be clarified.
1. system. ObjectC # all types are inherited from the system. Object type. Therefore, let's look at the code of the system. Object Type before talking about other content:
// Abstract: // supports all classes in the. NET Framework class hierarchy and provides low-level services for derived classes. This is the final base class of all classes in. NET Framework; it is the root of the type hierarchy. [Serializable] [classinterface (classinterfacetype. autodual)] [comvisible (true)] public class object {// Abstract: // initialize a new instance of the system. Object Class. [Reliabilitycontract (consistency. willnotcorruptstate, Cer. mayfail)] public object (); // Abstract: // determine whether the specified system. object is equal to the current system. object. //// Parameter: // OBJ: // system. Object compared with the current system. object. //// Return result: // true if the specified system. object is equal to the current system. object; otherwise, false. [Targetedpatchingoptout ("performance critical to inline upload SS ngen image boundaries")] Public Virtual bool equals (Object OBJ); /// Abstract: // determine whether to set the specified system. object instances are considered equal. //// Parameter: // obja: // The first system. object to be compared. //// Objb: // The second system. object to be compared. //// Return result: // true if the object is considered equal; otherwise, false. [Targetedpatchingoptout ("performance critical to inline upload SS ngen image boundaries")] public static bool equals (Object obja, object objb); // Abstract: // used as a hash function of a specific type. //// Returned result: // The hash code of the current system. object. [Targetedpatchingoptout ("performance critical to inline upload SS ngen image boundaries")] Public Virtual int gethashcode (); // Abstract: // obtain the system. Type of the current instance. //// Return result: // system. type indicates the exact runtime type of the current instance. [Securitysafecritical] public type GetType (); // Abstract: // create a superficial copy of the current system. object. //// Returned result: // a superficial copy of the current system. object. [Securitysafecritical] protected object memberwiseclone (); // Summary: // determine whether the specified system. object instance is the same instance. //// Parameter: // obja: // The first system. object to be compared. //// Objb: // The second system. object to be compared. //// Return result: // true if obja is the same as objb instance, or if both are empty references; otherwise, false. [Reliabilitycontract (consistency. willnotcorruptstate, Cer. success)] [targetedpatchingoptout ("performance critical to inline upload SS ngen image boundaries")] public static bool referenceequals (Object obja, object objb); // Abstract: // return indicates the current system. object System. string. //// Return result: // system. String, indicating the current system. object. Public Virtual string tostring ();}
From the code above, we can see that there are several basic methods of all types, namely the common method equals, gethashcode, tostring, GetType, and the protected method memberwiseclone and finalize. For details about the object class, see the msdn document http://msdn.microsoft.com/zh-cn/library/e5kfa45b C # to use the new operator to create an object, such as the class animal defined:
public class Animal { private string _name; public string Name { get; set; } public Animal() { //Do some thing } public Animal(string name) { _name = name; } }
Now we will discuss what happened during animal animalmodel = new animal ("Keli"); instantiation:
(1) first, the CLR needs to know the memory size of the instantiated object, so it will calculate the type and all its base classes (until system. object. In addition, all objects stored on the stack need two additional members: Type object pointer and sync block index ), so we need to include their bytes. By the way, the additional two members are used by the CLR to manage objects. In a word, the first step is to calculate the size of memory allocated to this object. (2) allocate memory of the specified size from the managed heap. (3) initialize two additional members of the object-type object pointer and synchronized block index (4), call the Type constructor (also, some parts are translated as "Constructor ", I used to call constructor, the same below) and pass in the parameters specified in the new call. When a constructor is called, it starts from the constructor call of the object class and starts from the level 1. Each constructor initializes the instance fields defined in this type. In this example, he calls system. Object. Object () and animal. Animal (string name ).
TIPS:We have a deep understanding of the execution sequence of the constructor. Therefore, we continue to construct a dog class, which inherits from animal: Public ClassDog: Animal { public Dog() { //Do some thing } public Dog(string name) { //_name = name; } public Dog(string name, int age) { //do some thing } } If dog dogmodel1 = new dog (); is executed, the execution sequence of the constructor is: System.Object.Object(); Animal.Animal(); Dog.Dog(); If dog dogmodel1 = new dog ("Keli"); is executed, the execution sequence of the constructor is: System.Object.Object(); Animal.Animal(); Dog.Dog(string name); If dog dogmodel1 = new dog ("Keli", 15); is executed, the execution sequence of the constructor is: System.Object.Object(); Animal.Animal(); Dog.Dog(string name, int age); If animal only has the animal. Animal (string name) constructor, the constructor in dog will report an error, and this is an error that will be discovered during the compilation phase, such:If you want to call the animal (string name) of the parent class animal when calling the dog constructor dog (string name), you need to make the following changes in the constructor: public Dog(string name) : base(name) { //_name = name; } In this way, when executing dog dogmodel1 = new dog ("Keli");, the call order is as follows: System.Object.Object(); Animal.Animal(string name); Dog.Dog(string name); Similarly, you can call another constructor of this class before calling the constructor, using the this keyword: public Dog(string name, int age) : this(name) { //do some thing } In this case, when executing dog dogmodel1 = new dog ("Keli");, the call order is as follows: System.Object.Object(); Animal.Animal(string name); Dog.Dog(string name); Dog.Dog(string name, int age); Do not deliberately write the execution sequence of the constructor into an endless loop, such: public Dog(string name) : this(name, 14) { //_name = name; } public Dog(string name, int age) : this(name) { //do some thing } No error is reported during compilation, but systemoverflowexception is reported during runtime. The error message is as follows: |
Ii. type conversionHere, the type conversion is not the conversion of the primitive type, but the basic type conversion. Type security is one of the most important features of CLR. Therefore, in type conversion, CLR also needs to confirm the conversion security before implicit conversion. Without confirming whether the conversion is secure, the programmer needs to forcibly convert the data. In this case, the programmer is responsible for all consequences. In fact, it is easy to sum up, that is, it is safe to convert all objects to their own base types, so they can be implicitly converted directly. However, if you convert to a derived type of your own, the conversion may fail, therefore, developers need to display the conversion. For example:
Object o = new Animal(); Animal a = (Animal)o; Dog d = (Dog)o;
In the first case in the third case above, because animal is a derived class of the object type, this conversion is implicit and safe. Although the variable O is of the object type, it actually points to an animal object in the managed heap;
The second case is that the object type is converted to its own derived class animal, so forced conversion is required. However, since O actually points to an animal object, such conversion is safe, therefore, this step does not report an error. In the third case, the object type is converted to the derived class of the derived class, which also needs to be forcibly converted. However, since O points to an animal object, the animal type is the parent class of the dog type and cannot be converted. Therefore, an error is returned during this step.
The AS and is operators in C #The is operator checks whether an object is compatible with the specified type. If yes, true is returned. Otherwise, false is returned. In fact, that is, whether the conversion can be successful or not with the specified type. For example:
BoolB1 = o
IsAnimal;
BoolB2 = o
IsDog;
B1 = true; b2 =
False;
Therefore, the is operator is generally used to determine whether a type can be safely converted to another type. For example:
If(O
Is
Animal)
{
Animal a2 =
(Animal) O;
}
But there is a drawback in writing this way, that is, in if, it will verify whether o can be converted to the animal type once, and it will be converted again in actual conversion, the type conversion has a certain impact on the performance, so we can use the as operator to simplify this code, which not only securely converts the type, but also saves performance.
As converts an object from one type to another type. If the conversion is successful, the object is converted to the target type. Otherwise, as returns NULL. As works in the same way as forced type conversion, but will never throw an exception because the exception will be suppressed and the result will be null. In this way, the above example can be converted:
a = o as Animal; if (a != null) { //Do something }
The above Code only converts the type once, that is, as. In the if statement, it only verifies whether instance a is null. This check consumes much less performance than type conversion.
Iii. namespace and assembly
1. namespace ):Namespaces are used to logically group related types. developers can use namespaces to conveniently locate a type. For example, if you have many documents on your computer, you need to create a directory for logic. These documents are divided into many categories, such as "learning materials" and "Movies, these classes are equivalent to the namespace we are talking about here. You can find a movie file in the future. When we use a certain type, we need the full name of this type, that is, we need to bring the namespace, but C # compiler in order to facilitate developers, the Using command is used to simplify our code. I believe that everyone understands this. C # When the compiler encounters a type during compilation, it will try to add the namespace in using to match in sequence. If the two namespaces have the same name as the nametype, you need to add the namespace to distinguish them when using this type. You can also use the namespace alias to solve this problem. For example, namespace1 and namespace2 both have the class1 type. You can use the following method when using this type:
using np1 = NameSpace1; using np2 = NameSpace2; np1.Class1 = null; np2.Class1 = null;
There is also an extreme case where the namespace name and the referenced type name are exactly the same, in which case you need to use the external alias feature. For specific use, see msdn: http://msdn.microsoft.com/zh-cn/library/ms173212.aspx
2. Assembly ):An assembly is a logical grouping of one or more modules/resource files. It is the minimum unit for reuse, security, and version control. Since the Assembly is not the focus of this series of discussions, for now only mention so much, you can refer to the "CLR via C #" Chinese third edition of The P6-P10.
3. Relationship between the namespace and the Assembly:Many children's shoes are entangled in this issue. I want to say that there is no need to compare it. They have almost nothing to do with it. An assembly can contain several namespaces, and a namespace can also be distributed in several datasets. For the time being, we can understand that the namespace just introduced an example of a document. If a namespace refers to a class that these documents are logically divided, the Assembly is the physical classification of these documents, such as disk C and disk D. Well, the basics of the type are summarized so much. Let's look back at most of the content in "CLR via C #". The right is the review of this book. Finally, I recommended this book again and wrote it well.