C # class member initialization sequence

Source: Internet
Author: User

C # as a pure object-oriented language, the entire code for it is inseparable from objects. The full life cycle of an object is from the initial allocation of space to initialization, to use, and finally to destruction. The resources used are recycled. To truly write high-quality code, we have to understand the status of each stage during this period, what the framework has done, and what we can do.
Generally, most programmers are clear about how to use a created object. Therefore, this article does not want to explain this part too much, the focus is on the two phases of object creation and destruction, which is also the easiest order for programmers to make mistakes. This article will first introduce the initialization of object members. As for the release and destruction of objects, I would like to introduce them in another article. Although this article uses C #2005 as an example, it should be the same for other CLS-based languages.

First, let's take a look at the initialization process of the reference type members.

Let's look at an example.

Class Program
{
Static void main (string [] ARGs)
{
Driveb d = new driveb ();
}
}

Class basea
{
Static displayclass A = new displayclass ("base class static member initialization ");

Displayclass basea_c = new displayclass ("base class instance variable basea_c initialization ");

Public basea ()
{
Console. writeline ("base class constructor called ");
}
}

Class driveb: basea
{
Static displayclass driveb_ B = new displayclass ("Inheriting class static member driveb_ B initialization ");

// Static basea driveb_a = new basea ();

Displayclass driveb_c = new displayclass ("Inheriting class instance variable driveb_c initialization ");

Public driveb ()
{
Console. writeline ("the inherited class constructor is called ");
}
}
Class displayclass
{
Public displayclass (string diplaystring)
{
Console. writeline (diplaystring );
Console. writeline ();
}
}


The result of the program's dynamic rows is:
Inheritance class static member driveb_ B Initialization
Class class instance variable driveb_c Initialization
Base Class static member Initialization
Base class instance variable basea_c Initialization
The base class constructor is called.
The inherited class constructor is called.

The initialization sequence is as follows:

1) inherit static member variable Initialization
2) inherit class instance variable Initialization
3) initialize static member variables of the base class
4) initialization of base class instance variables
5) base class constructor call
6) inherit class constructor call.

It seems that the result is a little different from that of Java. It's a bit confusing. I don't know why M $ wants initialization to be executed in this order, how nice is a strict base class to a derived class like Java. the running result of the above example shows that the constructor is different from the execution sequence of our general ideas. for instance Member initialization, perform the following steps:
Class 1 object initialization in general order instance members are assigned to constructors
2. The assignment of members is initialized in the order from subclass to parent class.
3. the initialization of the constructor follows the sequence from parent class to subclass.
From this point, we need to note that, because the initialization of the member assignment is from the subclass to the parent class, do not reference the members of the parent class during the initialization of the member assignment of the subclass, at this time, the parent class member has not started initialization. note that C # after the memory is allocated in the first step of object creation, all instance member variables will be initialized to the default value of the variable. For example, if the integer is 0, the reference type is null. the initialization process of member variables starts. C # does not provide special initialization methods similar to those in the C ++ constructor:
Public Constructor (int A) I _a (){}
It is estimated that the allocation of memory is strictly separated from the initialization, and reflection is required to create objects. It is not like C ++ that pursues extreme efficiency; and as we have seen in the past, good syntax-level optimization cannot change the efficiency of poorly written code.

We know that static member initialization in C # is different from static member initialization in C ++. the static member in C # Will initialize the static member only when necessary, specifically when the class is accessed for the first time. this is also true. First, the memory overhead is reduced, and then the Assembly startup time is accelerated, it is hard to imagine that a more time-consuming static initialization will be carried out one by one at the startup of the program, and such waiting will be quite painful. most of the time, we only use a small number of classes in an assembly. If we Initialize all classes in the Assembly in advance, the waste of memory and time is still relatively large.

After understanding the timing of static member initialization, another problem is raised. If the two classes reference each other, for example, Class A's static initialization references class B and class B's static
Class A is referenced in the initialization. What kind of results will be displayed at this time? I 'd like to explain it with examples. Please refer to the following code:

Using system;
Class
{
Public static int X;
Static (){
X = B .y + 1;
}
}
Class B
{
Public static int y = a.x + 1;
Static B (){}
Static void main (){
Console. writeline ("x = {0}, y = {1}", a.x, B .y );
}
}

What is the output result?

In general, the value assignment statement of the static declaration is executed before the static constructor. The class member declaration without the value assignment will be initialized to the default value of this type, that is
Public static int X;
Public static int y = a.x + 1;
The statement is executed before the static constructor. The first sentence X is not assigned a value. The default value is 0, after the value is assigned, it is the.x + 1 value.
Class static initialization includes the Declaration and assignment of member variables and the execution of static constructor.
Static Initialization is executed only when the class is accessed for the first time. It takes precedence over the code execution when the class is accessed for the first time.

Because the main function is in Class B, the program first executes the second statement above, declares a Y, and then assigns a value to y.
When assigning values, the X static in Class A is used again. When accessing a.x for the first time, the static constructor of Class A is called. Here, the value x = B .y + 1 is assigned, re-access the members of Class B, because the previously mentioned static initialization will be executed only when the class B is accessed for the first time, so the static initialization will not be repeated when the class B is accessed again. At this time, because the previous initialization has not been completed, especially B .y has not been assigned a value, so according to the above description, B .y is only in the declared state, so the B .y value is 0, the corresponding value of X is 1. When the static constructor of Class A is executed, the program will return to the value assignment statement of Y in Class B, at this time, the value of a.x is 1, and after the value of Y is assigned, the value is changed to 2.
Therefore, the final output result is x = 1, y = 2.

I have mentioned so much about the initialization of reference type members. Let's summarize it. in C #, initialization variables (including instance member variables and static member variables) can be assigned by the place declared by the member, or by the constructor. I personally recommend using the constructor method when using instance objects, because the execution sequence of constructor values is from parent class to subclass, this sequence avoids the reference of unassigned parent class member variables during initialization of subclass member variables. in addition, you can use more statement blocks and more judgment logic to initialize the initialization variables in the constructor. You can even add the structured exception handling try {} catch {} to process the exception information, it is far more flexible than a single value assignment statement. however, for simple built-in basic types (such as int, Enum, String, etc.), it doesn't matter where to initialize them.

The above is the initialization process of the reference type. The static initialization of the value type (here mainly refers to the structure type) is exactly the same as that of the reference type. the structure type of C # Is Constructor (remember that the constructor can be declared in the structure of C ++), and the initialization of instance members is because the structure does not have a derived function, therefore, this is relatively simple. however, because the value type cannot be blank, the corresponding memory space must be allocated once declared. With the memory space, Initialization is required first, this is to ensure the validity of the value type. this process is completed by the framework, and we have no way to write code to control it. therefore, when the framework initializes and calls the constructor itself, of course, it needs to make a unified convention on the parameters of the constructor to be called. The simplest thing is that there is no constructor. therefore, each structure in C # contains a non-argument constructor by default. programmers can reload constructor by themselves, however, you cannot declare your own no-argument Constructor (this is occupied by the Framework ).

Many programmers who have just switched from C ++ to C # can realize that they need to create an instance before using the reference type as a temporary variable of the function, however, when using a structure as a temporary variable of a function, I like to declare it and use it directly. When I ask them, I always say that the structure is a value type and the value type exists on the stack, it can be used directly after declaration. whether this sentence is correct or not (for C # Where does the Mean Value Type and reference type exist? I will write an article to discuss it later ). first, according to the C # programming specification, value types also require encapsulation of member variables. Many value types cannot be changed after being declared, if only one struct is declared and no value is assigned, it is equivalent to the default constructor called. Generally, this default constructor is meaningless to us. therefore, the obtained value is not very useful unless you want to use it as a real parameter of the out parameter. so when you use the struct in this way, the C # compiler will warn you that this variable only declares that no value is assigned (in fact, it is equivalent to a value, but it does not make sense ). in fact, it is also a good habit to assign values before using variables. Although it can be used directly declared in C ++, zeromemory is usually used before use, this is actually equivalent to initializing the struct. The only difference is that there is no need to re-allocate space.

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.