为什么不是';是否调用此C#实例构造函数,除非存在对非静态成员的引用?
此代码似乎没有调用为什么不是';是否调用此C#实例构造函数,除非存在对非静态成员的引用?,c#,static,.net-core,C#,Static,.net Core,此代码似乎没有调用Mixed构造函数并打印y=0 public class Mixed { public int x; public static int y; public Mixed() { x = 1; y = 1; } } public class Program { static Mixed mixed = new Mixed(); static void Main(string[]
Mixed
构造函数并打印y=0
public class Mixed
{
public int x;
public static int y;
public Mixed()
{
x = 1;
y = 1;
}
}
public class Program
{
static Mixed mixed = new Mixed();
static void Main(string[] args)
{
Console.WriteLine("y = " + Mixed.y);
Console.ReadLine();
}
}
但是,简单地修改Main
函数使其看起来像这样会导致调用构造函数
static void Main(string[] args)
{
Console.WriteLine("x = " + mixed.x);
Console.WriteLine("y = " + Mixed.y);
Console.ReadLine();
}
这张照片是:
x = 1
y = 1
为什么简单地将此引用添加到非静态字段会导致正确调用构造函数?创建对象不应该总是导致调用构造函数,而不管该对象以后在程序中如何使用吗
奇怪的是,像这样使Mixed
对象非静态也会导致调用构造函数:
public class Program
{
static void Main(string[] args)
{
Mixed mixed = new Mixed();
Console.WriteLine("y = " + Mixed.y);
Console.ReadLine();
}
}
然而,这对我来说似乎也没有意义。将
Mixed
对象声明为static应该只意味着内存中只有一个对象的副本,而不管程序实例化了多少次。这是某种编译器优化吗?对于静态字段,编译器在实际实例化它之前会等待对该类型的非静态字段的引用吗?您遇到的是,程序
类型的静态字段没有被初始化
您会发现,当第一次访问某一类型的任何静态字段时,它们都会被初始化。这在不同的运行时(.NET Framework、.NET Core、Mono)之间是一致的
如下面的IL代码所示,您的示例将生成一个初始化字段的.cctor
(静态构造函数)
.class public auto ansi beforefieldinit ConsoleApp1.Program
extends [System.Runtime]System.Object
{
.field private static class ConsoleApp1.Mixed mixed
// (...) omitted irrelevant methods
.method private hidebysig specialname rtspecialname static
void .cctor () cil managed
{
// Code size 11 (0xb)
.maxstack 8
IL_0000: newobj instance void ConsoleApp1.Mixed::.ctor()
IL_0005: stsfld class ConsoleApp1.Mixed ConsoleApp1.Program::mixed
IL_000a: ret
}
}
但是,不同意在什么时候初始化字段。例如,NET Core将在访问任何字段之前延迟加载这些字段。NET Framework将在访问任何类型的成员(包括方法)时急切地加载字段 以下代码在.NETCore和.NETFramework中具有不同的结果
public class Program
{
static Mixed mixed = new Mixed();
static string text = "Hello, World!";
static void Main(string[] args)
{
Console.WriteLine("y = " + Mixed.y);
Console.WriteLine(text);
Console.WriteLine("y = " + Mixed.y);
Console.ReadLine();
}
}
在.NET核心中:
y=0你好,世界
y=1 在.NET Framework中: y=1
你好,世界
y=1
如果向类中添加静态构造函数,则在访问任何字段或方法时,字段将始终初始化:
// ... adding to previous Program class
static Program()
{
// empty body
}
在.NET核心中:
y=1你好,世界
y=1 发生这种情况的原因是,
beforefieldinit
标志不会添加到具有自定义静态构造函数的类型中。此标志表示可以尽可能晚/晚加载类型的字段
当省略此标志时,字段将立即初始化。当标志出现时,字段至少会被延迟加载,但也可能被急切加载,这取决于运行时
如前所述,.NET Core将在标志出现时延迟加载字段。NET Framework将急切地加载字段,无论是否存在该标志。启用优化后,
new Mixed()
调用将被删除,因为您没有引用Mixed
。尝试在不进行优化(调试配置)的情况下运行代码,看看会发生什么。如果您有LINQPad,那么通过切换/o-标志来测试这是非常简单的。这是调试代码还是发布代码?“这段代码似乎没有调用混合构造函数并打印y=0
”-无法确认。代码为我打印1。构造函数中的断点被命中。在这两种情况下我都得到1。@Sinatr我在.NET Core中运行它,您使用的是什么运行时?VS 2015:File-New-Project-Visual C#Console应用程序。我不确定您为什么被否决,我得到的是相同的输出。谢谢,这是有道理的。静态字段初始化是有保证的。不同的运行时(.NET Framework、.NET Core、调试版本和发布版本)可能会实现不同的功能,只要它们遵循保证。但是,这一切都是因为程序中存在未引用的静态数据会让你感到头疼。