This article describes the usage of constructors and destructors in C#. Share it for your reference, as follows:
Constructor and destructor are two seemingly simpler functions in the same class, but there will always be some unexpected operation errors in actual application. This article will introduce the principles of constructors and destructors and their application in C#, as well as several things to pay attention to during use.
one. The principle of constructor and destructor
As a more advanced language than C, C# provides better mechanisms to enhance program security. The C# compiler has strict type safety checking capabilities, which can find almost all syntax problems in the program, which does help programmers a lot. However, the program passes the compilation check and does not mean that the error no longer exists. In the "error" family, the status of "grammatical errors" can only be regarded as the tip of the iceberg. High-level errors are usually hidden very deeply and are not easy to detect.
According to experience, many difficult-to-know program errors are caused by the fact that the variables are not initialized or cleared correctly, and the initialization and clearance work is easily forgotten. Microsoft used the object-oriented concept to fully consider this problem when designing C# languages and solved it well: put the initialization of objects in the constructor and the clearing of objects in the destructor. When an object is created, the constructor is executed automatically. When the object dies, the destructor is executed automatically. This way you don't have to worry about forgetting the initialization and cleaning of the object.
two. Application of constructors in C#
The name of the constructor cannot be randomly named, and it must be recognized by the compiler before it can be executed automatically. Its naming method is both simple and reasonable: make the constructor the same name as the class. Apart from the name, another special thing about the constructor is that there is no return value type, which is different from a function whose return value type is void. If it has a return value type, the compiler will be overwhelmed. Before you can access a class's methods, properties, or anything else, the first statement executed is a constructor containing the corresponding class. Even if you don't write a constructor yourself, there will be a default constructor for you.
The following lists several types of constructors
1) Default constructor
class TestClass { public TestClass(): base() {} }
As mentioned above, it is provided by the system (CLR).
2) Instance constructor
An instance constructor is a method member that implements initialization of instances in a class. like:
using System; class Point { public double x, y; public Point() { = 0; = 0; } public Point(double x, double y) { = x; = y; } … } class Test { static void Main() { Point a = new Point(); Point b = new Point(3, 4); // Initialize the object with a constructor… } }
Declares a class Point, which provides two constructors. They are overloaded. One is the Point constructor without parameters and the other is the Point constructor with two double parameters. If these constructors are not provided in the class, the CLR will automatically provide a default constructor. But once custom constructors are provided in the class, such as Point() and Point (double x, double y), the default constructor will not be provided, so be careful.
3) Static constructor
A static constructor is a method member that implements initialization of a class. It is generally used to initialize static data. A static constructor cannot have parameters, modifiers and cannot be called. When the class is loaded, the static constructor of the class is automatically called. like:
using ; class Employee { private static DataSet ds; static Employee() { ds = new DataSet(...); } ... }
Declares a class Employee with a static constructor. Note that static constructors can only initialize static data members, but cannot initialize non-static data members. However, non-static constructors can either assign values to static data members or initialize non-static data members.
If the class contains only static members, you can create a private constructor: private TestClass() {…}, but private means that it is impossible to access the constructor from outside the class. Therefore, it cannot be called, and no object can be instantiated by the class definition.
The above are simple uses of several types of constructors. The following will focus on how to use the constructors of base classes and derived classes in the class hierarchy (i.e., in the inheritance structure). The initialization of derived class objects is done by the base class and derived class: the members of the base class are initialized by the constructor of the base class, and the members of the derived class are initialized by the constructor of the derived class.
When creating an object of a derived class, the system will call the base class constructor and the derived class constructor. The order of execution of the constructor is: first execute the base class constructor, and then execute the derived class constructor. If the derived class has object members, first execute the constructor of the base class, then execute the constructor of the member object class, and finally execute the constructor of the derived class.
As for what constructor to execute the base class, by default, it is the non-argument constructor of the base class. If you want to execute the parameter constructor of the base class, it must be pointed out in the member initialization table of the derived class constructor. like:
class A { private int x; public A( ) { x = 0; } public A( int i ) { x = i; } } class B : A { private int y; public B( ) { y = 0; } public B( int i ) { y = i; } public B( int i, int j ):A(i) { y = j; } } B b1 = new B(); //Execute the constructor A() of base class A, and then execute the constructor B() of derived classB b2 = new B(1); //Execute the constructor A() of base class A, and then execute the constructor B(int) of derived classB b3 = new B(0,1); //Execute the constructor A(int) that executes the base class A, and then executes the constructor B(int,int) of the derived class
The execution order of constructors here must be clearly analyzed. In addition, if the parameterless constructor public A( ) { x = 0; } is not provided in base class A, then the parameterless constructor A(i) of base class A must be pointed out in the initialization table of all constructor members of the derived class, as shown below:
class A { private int x; public A( int i ) { x = i; } } class B : A { private int y; public B():A(i) { y = 0; } public B(int i):A(i) { y = i; } public B(int i, int j):A(i) { y = j; } }
three. The application of destructors and garbage collectors in C#
A destructor is a method member that implements the destruction of an instance of a class. The destructor cannot have parameters, cannot have any modifiers and cannot be called (it is automatically called by the system). Since the purpose of the destructor is opposite to the constructor, the prefix ‘~’ is added to indicate the difference.
Although C# (more precisely, CLR) provides a new memory management mechanism - automatic memory management mechanism, the release of resources can be automatically completed through the "garbage collector" and generally does not require user intervention, but in some special cases, destructors are still needed, such as the release of unmanaged resources in C#.
Release of resources is generally done automatically through the "garbage collector", but specifically, there are still some things that need to be paid attention to:
1. References of value types and reference types do not actually require a "garbage collector" to free up memory, because they will automatically release the memory when they are scoped, because they are all stored in the stack (Stack);
2. Only the object instance pointed to by the reference type reference is stored in the heap. Because the heap is a free storage space, it does not have a lifetime like the "stack" (the element of the "stack" pops up to indicate the end of the lifetime, which means the memory is released). It should be noted that the "garbage collector" only works for this area;
However, in some cases, when unmanaged resources need to be released, it must be solved by writing code. Usually, use the destructor to release unmanaged resources, and place the code segment written by the user to release unmanaged resources in the destructor. It should be noted that if a class does not use unmanaged resources, then you must not define the destructor. This is because the object executes the destructor. Then the "garbage collector" must call the destructor before releasing the managed resources, and then the managed resources will be truly released the second time. In this way, the cost of two deletions is greater than that of one. Here is a piece of code to illustrate how the destructor is used:
public class ResourceHolder { … ~ResourceHolder() { // Here is the user code segment for cleaning up unmanaged resources} }
Four. summary
Although constructors and destructors are relatively simple functions in a class, their use is by no means as simple as it seems. Therefore, flexible and correct use of constructors and destructors can help you better understand the memory management mechanism of CLR and better manage resources in the system.
Note: CLR
CLR (Common Language Runtime Library) is also a runtime environment like Java virtual machines. It is responsible for resource management (memory allocation and garbage collection) and ensures the necessary separation between the application and the underlying operating system.
In order to improve the reliability of the platform and to achieve the level of stability required by transaction-oriented e-commerce applications, CLR is also responsible for some other tasks, such as monitoring the operation of the program. According to .NET, programs running under CLR monitoring belong to "managed" code, and applications or components that are not under CLR and directly run on bare metal belong to "unmanaged" code.
CLR will monitor a variety of common programming errors that have been the main source of software failures for many years, including access to array elements, access to unallocated memory space, memory overflows due to excessive data size, and so on.
For more information about C# related content, please check out the topic of this site:Summary of thread usage techniques for C# programming》、《Summary of C# operation skills》、《Summary of XML file operation skills in C#》、《Tutorial on the usage of common C# controls》、《Summary of WinForm control usage》、《C# data structure and algorithm tutorial》、《Summary of C# array operation skills"and"Introduction to C# object-oriented programming tutorial》
I hope this article will be helpful to everyone's C# programming.