英文:
.net 5.0 VS .net framework 4.6 different behavior
问题
在.NET Framework 4.6中运行此代码时,只会得到"press any key.",但在.NET 5.0中可以得到"config changed.",为什么?
在.NET Framework的逻辑中,所有的静态成员在第一次被引用时都会被初始化:https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/static-classes-and-static-class-members
程序无法指定类在何时加载。但是,保证在程序中首次引用类之前,该类已被加载,其字段已被初始化,并且其静态构造函数已被调用。
似乎这个逻辑在.NET Core中不可用,是否有官方文件?
在.NET 5.0以后,这个行为已经改变,不再保证在类第一次被引用时立即初始化静态成员。这是.NET Framework和.NET Core之间的一个区别。
至于官方文件,您可以查看.NET 5.0及以后的官方文档,以了解更多关于这种行为变化的信息。
英文:
Notes this code, when run it in .net framework 4.6, only get "press any key.", but can get "config changed." in .net 5.0, why?
public class Holder
{
public static int IntVal = 0;
public static DateTime DateTimeVal;
}
public class StaticDateTime
{
private static DateTime config = DateTime.Now;
public StaticDateTime()
{
}
public void configChanged()
{
DateTime d = Holder.DateTimeVal;
if (d.Ticks == 0)
{
Holder.DateTimeVal = DateTime.Now;
return;
}
if (d < config)
{
Console.WriteLine("config changed.");
}
}
}
class Program
{
static void Main(string[] args)
{
StaticDateTime sd = new StaticDateTime();
sd.configChanged();
System.Threading.Thread.Sleep(1500);
StaticDateTime sd2 = new StaticDateTime();
sd2.configChanged();
Console.WriteLine("press any key.");
Console.ReadKey();
}
}
in .net framework's logic, all the static members will be initialized at the first time when it is referenced: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/static-classes-and-static-class-members
> The program cannot specify exactly when the class is loaded. However, it is guaranteed to be loaded and to have its fields initialized and its static constructor called before the class is referenced for the first time in your program.
It seems this logic is not avalible in .net core, is there any official documents?
答案1
得分: 5
以下是您要翻译的代码部分:
That quoted paragraph is slightly too loose. It's entirely possible to execute code in a method without initializing its containing class. If the class doesn't have a static constructor, class initialization *must* happen at some point before the first reference to a static field, and before the first instance is created - but it can happen at any point up until then.
Here's a somewhat simpler way of reproducing that:
```csharp
using System;
class Program
{
static int field = ReportInitialization();
private static int ReportInitialization()
{
Console.WriteLine("Field initializer called");
return 5;
}
static void Main()
{
Console.WriteLine("Before field reference");
int f = field;
Console.WriteLine($"Field value: {f}");
}
}
In .NET 6.0 on my machine, this prints:
Before field reference
Field initializer called
Field value: 5
In .NET 4.6.2 on my machine, this prints:
Field initializer called
Before field reference
Field value: 5
If you add a static constructor (static Program(){}
) then both have the same output as .NET 4.6.2 above.
The C# standard has a more precise phrasing. From section 14.5.62:
> The static field variable initializers of a class correspond to a sequence of assignments that are executed in the textual order in which they appear in the class declaration (§14.5.6.1). Within a partial class, the meaning of “textual order” is specified by §14.5.6.1. If a static constructor (§14.12) exists in the class, execution of the static field initializers occurs immediately prior to executing that static constructor. Otherwise, the static field initializers are executed at an implementation-dependent time prior to the first use of a static field of that class.
Section 14.12 on static constructors states:
> The static constructor for a closed class executes at most once in a given application domain. The execution of a static constructor is triggered by the first of the following events to occur within an application domain:
>
> - An instance of the class is created.
> - Any of the static members of the class are referenced.
<details>
<summary>英文:</summary>
That quoted paragraph is slightly too loose. It's entirely possible to execute code in a method without initializing its containing class. If the class doesn't have a static constructor, class initialization *must* happen at some point before the first reference to a static field, and before the first instance is created - but it can happen at any point up until then.
Here's a somewhat simpler way of reproducing that:
```csharp
using System;
class Program
{
static int field = ReportInitialization();
private static int ReportInitialization()
{
Console.WriteLine("Field initializer called");
return 5;
}
static void Main()
{
Console.WriteLine("Before field reference");
int f = field;
Console.WriteLine($"Field value: {f}");
}
}
In .NET 6.0 on my machine, this prints:
Before field reference
Field initializer called
Field value: 5
In .NET 4.6.2 on my machine, this prints:
Field initializer called
Before field reference
Field value: 5
If you add a static constructor (static Program(){}
) then both have the same output as .NET 4.6.2 above.
The C# standard has a more precise phrasing. From section 14.5.62:
> The static field variable initializers of a class correspond to a sequence of assignments that are executed in the textual order in which they appear in the class declaration (§14.5.6.1). Within a partial class, the meaning of “textual order” is specified by §14.5.6.1. If a static constructor (§14.12) exists in the class, execution of the static field initializers occurs immediately prior to executing that static constructor. Otherwise, the static field initializers are executed at an implementation-dependent time prior to the first use of a static field of that class.
Section 14.12 on static constructors states:
> The static constructor for a closed class executes at most once in a given application domain. The execution of a static constructor is triggered by the first of the following events to occur within an application domain:
>
> - An instance of the class is created.
> - Any of the static members of the class are referenced.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论