[You must know. NET] 23rd back: taste details, go deep into the. NET Type constructor

Source: Internet
Author: User
Tags mscorlib

You must know. NET

. NET website you must know|Anytao technology blog

[You must know. NET] 23rd back: taste details, go deep into the. NET Type constructor

Released on: 2008.11.2 by: Anytao
2008 Original Works of Anytao.com and Anytao. Please refer to the author and source in the post.

Before
Today, Artech's question about Type Initializer and BeforeFieldInit allows us to understand an interesting example of calling and executing a Type constructor, some discussions about beforefieldinit's time to call the Type constructor are also raised, which provides a good practical experience for us to understand the Type constructor.
Recognize the Type constructor and beforefieldinit, pay more attention to the CLR execution mechanism, and taste the beauty of details.
1 Introduction

Today, Artech's question about Type Initializer and BeforeFieldInit allows us to understand an interesting example of calling and executing a Type constructor, some discussions about beforefieldinit's time to call the Type constructor are also raised, which provides a good practical experience for us to understand the Type constructor.
As a supplement, this article hopes to go further from the ground up and look at the concepts and principles not explained in "questions about Type Initializer and BeforeFieldInit to see if you can give a correct explanation, make necessary supplements, such as a more comprehensive understanding of the Type constructor, understanding BeforeFieldInit. On this basis, we will discuss some practical applications of the Type constructor and hope to answer the example running results.
Let's get started.

2. Recognize object constructor and Type constructor

In. NET, the initialization process of a class is carried out in the constructor. According to the type of the constructor, the constructor and object constructor are divided into two types. The. cctor and. ctor are the instructions in the IL code .. Cctor cannot be called directly. Its calling rules are the focus of this Article. For details, see the analysis in the following section. The. Tor will be automatically called during type instantiation.
Based on the discussion of the Type constructor, we need to first implement a simple class definition, including common constructor and static constructor, such

    // Release : code01, 2008/11/02                
    // Author  : Anytao, http://www.anytao.com 
    public class User
    {
        static User()
        {
            message = "Initialize in static constructor.";
        }
 
        public User()
        {
            message = "Initialize in normal construcotr.";
        }
 
        public User(string name, int age)
        {
            Name = name;
            Age = age;
        }
 
        public string Name { get; set; }
 
        public int Age { get; set; }
 
        public static string message = "Initialize when defined.";

We decompile the above Code into the IL code using the ildasm.exe tool, so that we can easily find the shadow of the corresponding Type constructor and object constructor,

Then, let's take a look at the concepts of object constructors and type constructors.

  • Object constructor (. ctor)

In the generated IL code, you can see the corresponding ctor. When the type is instantiated, the corresponding constructor is executed to initialize the type.
For more information about the instantiation process, design the complex execution sequence and initialize the process at the basic type level, see what you must know. NET section 7.8 "between static and static" has a detailed introduction and analysis, which will not be discussed too much in this article.
This article focuses on the Type constructor, so we will not discuss it too much here.

  • Type constructor (. cctor)

It is used to initialize static members. In. NET, the type will call. cctor in two cases:

  • Specify an initial value for a static member. For example, if only the static member is initialized in the previous example, but no static constructor is available, the. cctor IL code is implemented as follows:
.method private hidebysig specialname rtspecialname static 
        void  .cctor() cil managed
{
  // Code size       11 (0xb)
  .maxstack  8
  IL_0000:  ldstr      "Initialize when defined."
  IL_0005:  stsfld     string Anytao.Write.TypeInit.User::message
  IL_000a:  ret
} // end of method User::.cctor
  • Implement an explicit static constructor. For example, if a static constructor exists in the preceding example, the initialization process of the static member is executed first, and then the initialization process of the static constructor is executed ,. the implementation of the cctor IL code is:
.method private hidebysig specialname rtspecialname static 
        void  .cctor() cil managed
{
  // Code size       23 (0x17)
  .maxstack  8
  IL_0000:  ldstr      "Initialize when defined."
  IL_0005:  stsfld     string Anytao.Write.TypeInit.User::message
  IL_000a:  nop
  IL_000b:  ldstr      "Initialize in static constructor."
  IL_0010:  stsfld     string Anytao.Write.TypeInit.User::message
  IL_0015:  nop
  IL_0016:  ret
} // end of method User::.cctor

At the same time, we must clarify some basic rules for static constructors, including:

  • It must be a static, no-argument constructor and only one class can be created.
  • Only static members can be initialized.
  • Static and non-static constructors can coexist. The difference lies in the execution time of the two constructors. For details, see what you must know. NET section 7.8 "between static and static". For more differences and differences, see the description in this section.

3. In-depth Execution Process

Due to the characteristics of the Type constructor, it is determined to some extent that the call time of. cctor is not a definite concept. Because the Type constructor is private, you cannot explicitly call the Type constructor. Therefore, the execution time of the Type constructor mainly includes two methods in. NET:

  • Precise Mode
  • Beforefieldinit Method

The difference between the two statements mainly lies in whether explicit static constructor is implemented for the type. If an explicit static constructor is implemented, it is executed in precise mode; if an explicit static constructor is not implemented, it is executed in beforefieldinit mode.
To clearly understand the execution of the Type constructor, we must first define a premise in terms of concept, that is, the meaning of precise is clear. there is a precise relationship between the call of cctor and the access time of static members. In other words, the execution time of the Type constructor depends on whether the static constructor is explicitly declared, and the time to access static members.
Let's start with the implementation of the User class and analyze the execution process of these two methods one by one.
3.1 precise mode
First, implement an explicit static constructor scheme, which is:

    // Release : code02, 2008/11/02                
    // Author  : Anytao, http://www.anytao.com 
    public class User
    {
        //Explicit Constructor
        static User()
        {
            message = "Initialize in static constructor.";
        }
 
        public static string message = "Initialize when defined.";
    }

The corresponding IL code is:

.class public auto ansi User
    extends [mscorlib]System.Object
{
    .method private hidebysig specialname rtspecialname static void .cctor() cil managed
    {
        .maxstack 8
        L_0000: ldstr "Initialize when defined."
        L_0005: stsfld string Anytao.Write.TypeInit.User::message
        L_000a: nop 
        L_000b: ldstr "Initialize in static constructor."
        L_0010: stsfld string Anytao.Write.TypeInit.User::message
        L_0015: nop 
        L_0016: ret 
    }
 
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
        .maxstack 8
        L_0000: ldarg.0 
        L_0001: call instance void [mscorlib]System.Object::.ctor()
        L_0006: ret 
    }
 
    .field public static string message
}

For comparative analysis, we need to first analyze the execution of beforefieldinit, so proceed...
3.2 beforefieldinit
It is of the User type and does not implement an explicit static constructor scheme. It is:

    // Release : code03, 2008/11/02                
    // Author  : Anytao, http://www.anytao.com 
    public class User
    {
        //Implicit Constructor
        public static string message = "Initialize when defined.";
    }

The corresponding IL code is:

.class public auto ansi beforefieldinit User
    extends [mscorlib]System.Object
{
    .method private hidebysig specialname rtspecialname static void .cctor() cil managed
    {
        .maxstack 8
        L_0000: ldstr "Initialize when defined."
        L_0005: stsfld string Anytao.Write.TypeInit.User::message
        L_000a: ret 
    }
 
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
        .maxstack 8
        L_0000: ldarg.0 
        L_0001: call instance void [mscorlib]System.Object::.ctor()
        L_0006: ret 
    }
 
    .field public static string message
}

3.3 analyze differences
From the execution process of the IL code, we can first understand that in the explicit and implicit implementation of the Type constructor, in addition to adding new initialization operations, the implementation of the two is basically the same. Therefore, we need to find out the difference between the two methods. In the end, we will focus on the declaration of the two metadata. The implicit method is an additional command called the beforefieldinit tag.
So what semantics does beforefieldinit represent? Scott Allen explained this in detail: beforefieldinit provides CLR with the permission to execute. cctor at any time, as long as the method is executed before the static field of the first access type.
Therefore, if we compare the precise and beforefieldinit modes, the difference between them is whether the beforefieldinit command is marked during the metadata declaration. In precise mode, CLR must execute the Type constructor before accessing the static or instance members of this type for the first time, that is to say, you must call the Type constructor just before accessing static members or creating instance members. In beforefieldinit mode, CLR can execute the Type constructor at any time, to some extent, the execution performance is optimized, so it is more efficient than the precise method.
It is worth noting that when multiple beforefieldinit constructors exist, CLR cannot guarantee the execution sequence between these constructors, therefore, we should try to avoid this situation during actual encoding.

4. Summary of Regression Problems

This article is due to a problem of Artech brother. We hope that the above analysis can provide a reference background. Now let's take a look at the questions about Type Initializer and BeforeFieldInit to see if you can give a correct explanation of the following examples for further analysis:

  • In the example implementation at the beginning of brother Jiang, it is easy to determine that when a static constructor is explicitly implemented, the call of the Type constructor occurs before a static member is referenced, so whether it is declared in Main or not
string field = Foo.Field;

The execution result is not affected.

  • Without explicitly implementing static constructor, beforefieldinit optimizes that the execution of the Type constructor is not performed at a specified time, as long as it is a real static member reference or a type instance occurs, therefore, the call time in the Debug environment becomes unreasonable. However, in the Release optimization mode, the execution sequence of beforefieldinit is not subject
string field = Foo.Field;

Is fully compliant with the semantic definition of beforefieldinit optimization execution.

  • The result of the last static member inheritance is similar to the logic described in this article. The Type constructor occurs when a static member is called or an instance is created, therefore, the results of the example are fully compliant with the specifications. However, I do not recommend that sub-classes do not call static members of the parent class because as an inheritance mechanism, sub-parent is the basic inheritance specification, except for being forced to private, all the members or methods should be visible in the subclass. For potential problems, it may be better to constrain the potential problems with specifications. Static methods are structured implementation mechanisms to some extent. In the object-oriented inheritance relationship, there are some shortcomings in nature.
  • In the c # specification, beforefieldinit control has aroused a lot of attention and criticism. On the one hand, beforefieldinit can effectively optimize the call performance, however, the explicit and implicit implementation of static constructor methods cannot be more intuitive for program developers to Control. Therefore, in later versions of c, it is worth looking forward to implementing the feature-based declarative control.
  • On the other hand, when two types of constructors reference each other, CLR cannot guarantee the call sequence of the Type constructor. For program developers, I also stressed that for the Type constructor, we should try to avoid requiring sequence-related business logic, because the execution sequence is not declared sequence in many cases, which deserves attention.

5 conclusion

In addition to the questions about the Artech dude, this article continues on the Type constructor in "you must know. NET section 7.8 "between static and non-static", to further illustrate this issue from a more comprehensive perspective. At last, the question about calling optimization of the Type constructor caused by beforefieldinit flag is not fully 100% familiar with CLR calling behavior in Debug mode, however, we can understand more about the language in depth. From this point, this article is the beginning.

 

Anytao | 2008 Anytao.com

| Honors: http://www.cnblogs.com/anytao

This document is provided as "the status quo" without any guarantee and does not grant any rights. | This posting is provided "as is" with no warranties, and confers no rights.

The copyright of this article is owned by the author. You are welcome to repost this article, but you must keep this statement without the author's consent and provide a clear link to the original article on the article page. Otherwise, you will be entitled to pursue legal liability.

 

References

  • Section 7.8 "static and non-static"
  • Artech, for more information about Type Initializer and BeforeFieldInit, see if you can give a correct explanation.
  • Benefit from static content with seven key programming skills

    Learn more

    [Opening useful]
    [First: resentment: is and as]
    [Second: Abstract programming: interfaces and abstract classes]
    [Third: Historical entanglement: Characteristics and attributes]
    [Forth: Back-to-Back: class and struct]
    [Fifth: Let's look at the keywords-new]
    [Sixth: Let's look at the keywords-base and this]
    [7: taste type-starting from general type system]
    [Eighth time: taste type-value type and reference type (top)-memory rational]
    [Ninth: taste type-value type and reference type (medium)-unlimited Rules]
    [10: taste type-value type and reference type (lower)-Application journey]
    [11th: confusing parameters-art of transmission (I)]
    [12th: confusing parameters-art of transmission (lower)]
    [13th back: Starting from Hello, world to know IL]
    [14th: Get to know the IL code-from the beginning to now]
    [15th back: Inheriting the essence]
    [16th]
    [17th]
    [18th back: Object creation beginning and end (on)]
    [19th back: Object creation beginning and end (bottom)]
    [20th: learning methodology]
    [21st: null]
    [22nd: String resident (on) --- thinking with questions]

  • 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.