c# - 为什么 CLR 不总是调用值类型构造函数

标签 c# struct clr static-constructor typeinitializer

我有一个关于值类型中的类型构造函数的问题。这个问题的灵感来自 Jeffrey Richter 通过 C# 3rd ed 在 CLR 中写的东西,他说(在第 195 页 - 第 8 章)你永远不应该在值类型中定义类型构造函数,因为有时 CLR 不会调用

因此,例如(好吧......实际上是 Jeffrey Richters 的例子),即使通过查看 IL,我也无法弄清楚为什么在以下代码中没有调用类型构造函数:

internal struct SomeValType
{
    static SomeValType()
    {
        Console.WriteLine("This never gets displayed");
    }
    public Int32 _x;
}
public sealed class Program
{
    static void Main(string[] args)
    {
        SomeValType[] a = new SomeValType[10];
        a[0]._x = 123;
        Console.WriteLine(a[0]._x);     //Displays 123
    }
}

所以,对类型构造函数应用以下规则我只是不明白为什么上面的值类型构造函数根本没有被调用。

  1. 我可以定义一个静态值类型构造函数来设置类型的初始状态。
  2. 一个类型只能有一个构造函数——没有默认构造函数。
  3. 类型构造函数是隐式私有(private)的
  4. JIT 编译器检查该类型的类型构造函数是否已在此 AppDomain 中执行。如果不是,它会发出对 native 代码的调用,否则它不会发出调用,因为它知道该类型已经“初始化”。

所以...我只是想不通为什么我看不到正在构造的这种类型数组。

我最好的猜测是它可能是:

  1. CLR 构造类型数组的方式。我本以为在创建第一个项目时会调用静态构造函数
  2. 构造函数中的代码没有初始化任何静态字段,所以它被忽略了。我已经尝试在构造函数中初始化私有(private)静态字段,但该字段仍然是默认的 0 值 - 因此不会调用构造函数。
  3. 或者...由于设置了公共(public) Int32,编译器以某种方式优化了构造函数调用 - 但这充其量只是一个模糊的猜测!!

抛开最佳实践等不谈,我只是对它非常感兴趣,因为我想亲眼看看为什么它没有被调用。

编辑:我在下面添加了我自己的问题的答案,只是引用了 Jeffrey Richter 所说的话。

如果有人有任何想法,那就太好了。 非常感谢, 詹姆斯

最佳答案

Microsoft C#4 Spec与以前的版本略有不同,现在更准确地反射(reflect)了我们在这里看到的行为:

11.3.10 Static constructors

Static constructors for structs follow most of the same rules as for classes. The execution of a static constructor for a struct type is triggered by the first of the following events to occur within an application domain:

  • A static member of the struct type is referenced.
  • An explicitly declared constructor of the struct type is called.

The creation of default values (§11.3.4) of struct types does not trigger the static constructor. (An example of this is the initial value of elements in an array.)

ECMA SpecMicrosoft C#3 Spec两者在该列表中都有一个额外事件:“引用了结构类型的实例成员”。 所以看起来 C#3 在这里违反了它自己的规范。 C#4 规范已与 C#3 和 4 的实际行为更加一致。

编辑...

经过进一步调查,似乎几乎所有实例成员访问直接字段访问都会触发静态构造函数(至少在 C#3 和 4 的当前 Microsoft 实现中是这样)。 p>

因此,当前的实现与 ECMA 和 C#3 规范中给出的规则的相关性比 C#4 规范中的规则更紧密:在访问所有实例成员时,C#3 规则得到了正确的实现 except 字段; C#4 规则正确实现了字段访问。

(当涉及到与静态成员访问和显式声明的构造函数相关的规则时,不同的规范都是一致的——并且显然已正确实现。)

关于c# - 为什么 CLR 不总是调用值类型构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3246078/

相关文章:

c++ - sizeof 不会显示实际大小,尝试实现 ip

c++ - getline 不接受任何输入

.net - 装箱和拆箱是否有相同的性能影响?

c# - "final"在 IL 中是什么意思?

c# - 如何查找 JToken 是否包含值?

c# - 为什么 Visual Studio 的智能感知不适用于派生类?

c - struct 的 unsigned int 字段自动初始化了吗?

c# - .Net如何允许将Nullables设置为Null

c# - 删除字符串特定部分的数字(括号内)

c# - 对象初始化器和动态指定属性