C# 为什么';t CLR始终调用值类型构造函数
我有一个关于值类型中的类型构造函数的问题。这个问题的灵感来源于Jeffrey Richter通过C#3rd ed在CLR中写的东西,他说(在第195页-第8章),你永远不应该在值类型中定义类型构造函数,因为有时候CLR不会调用它 因此,例如(实际上是Jeffrey Richters的例子),即使通过查看IL,我也无法理解为什么在以下代码中没有调用类型构造函数:C# 为什么';t CLR始终调用值类型构造函数,c#,struct,clr,static-constructor,typeinitializer,C#,Struct,Clr,Static Constructor,Typeinitializer,我有一个关于值类型中的类型构造函数的问题。这个问题的灵感来源于Jeffrey Richter通过C#3rd ed在CLR中写的东西,他说(在第195页-第8章),你永远不应该在值类型中定义类型构造函数,因为有时候CLR不会调用它 因此,例如(实际上是Jeffrey Richters的例子),即使通过查看IL,我也无法理解为什么在以下代码中没有调用类型构造函数: internal struct SomeValType { static SomeValType() {
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
}
}
因此,对类型构造函数应用以下规则,我就是不明白为什么上面的值类型构造函数根本没有被调用
James我猜您正在创建一个值类型的数组。因此,new关键字将用于初始化数组的内存 可以这么说
SomeValType i;
i._x = 5;
在任何地方都没有新的关键字,这基本上就是你在这里做的。如果SomeValType是引用类型,则必须使用
array[i] = new SomeRefType();
根据本标准第18.3.10条(另见手册): 结构的静态构造函数的执行由应用程序域中发生的以下第一个事件触发:
- 结构的实例成员是 参考
- 固定成员 结构被引用
- 函数的显式声明的构造函数 结构被调用
在测试之后,一致的意见似乎是,它始终会触发方法、属性、事件和索引器。这意味着它对于除字段之外的所有显式实例成员都是正确的。因此,如果选择微软的C#4规则作为标准,这将使它们的实现从基本正确变为基本错误。更新:我的观察是,除非使用静态,否则将永远不会触及静态构造函数——这似乎是运行时决定的,不适用于引用类型。这就引出了一个问题:它是因为影响很小而留下的一个bug,是设计造成的,还是一个挂起的bug 更新2:就个人而言,除非您在构造函数中做了一些古怪的事情,否则运行时的这种行为永远不会导致问题。一旦您访问静态,它就会正常工作 更新3:进一步引用LukeH的评论,并参考Matthew Flaschen的答案,在结构中实现并调用自己的构造函数也会触发调用静态构造函数。这意味着,在三种情况中,有一种情况下,行为与锡上所说的不同 我只是在类型中添加了一个静态属性,并访问了该静态属性——它称为静态构造函数。如果不访问static属性,只创建该类型的新实例,就不会调用静态构造函数
internal struct SomeValType
{
public static int foo = 0;
public int bar;
static SomeValType()
{
Console.WriteLine("This never gets displayed");
}
}
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
// Doesn't hit static constructor
SomeValType v = new SomeValType();
v.bar = 1;
// Hits static constructor
SomeValType.foo = 3;
}
}
内部结构SomeValType
{
公共静态int foo=0;
公共酒吧;
静态SomeValType()
{
Console.WriteLine(“这永远不会显示”);
}
}
静态类程序
{
///
///应用程序的主要入口点。
///
[状态线程]
静态void Main()
{
//不会命中静态构造函数
SomeValType v=新的SomeValType();
v、 bar=1;
//命中静态构造函数
SomeValType.foo=3;
}
}
此链接中的一个注释指定,仅在访问实例时不调用静态构造函数:
MSIL中“beforefieldinit”属性的设计行为让人抓狂。它也会影响C++/CLI,我提交了一份错误报告,Microsoft在报告中很好地解释了这种行为的原因,并指出语言标准中有多个部分不同意/需要更新以描述实际行为。但这是不公开的。无论如何,这里是微软关于它的最后一句话(在C++/CLI中讨论类似的情况): 因为我们正在调用标准 这里是分区I的第8.9.5行 他说: 如果标记为BeforeFieldInit,则 类型的初始值
struct S
{
public int x;
static S()
{
Console.WriteLine("static S()");
}
public void f() { }
}
static void Main() { new S().f(); }