是否应在调用构造函数之前完成静态字段初始化?
以下程序提供的输出似乎对我不正确.
new A()
_A == null
static A()
new A()
_A == A
Run Code Online (Sandbox Code Playgroud)
代码:
public class A
{
public static string _A = (new A()).I();
public A()
{
Console.WriteLine("new A()");
if (_A == null)
Console.WriteLine("_A == null");
else
Console.WriteLine("_A == " + _A);
}
static A()
{
Console.WriteLine("static A()");
}
public string I()
{
return "A";
}
}
class Program
{
static void Main(string[] args)
{
var a = new A();
}
}
Run Code Online (Sandbox Code Playgroud) DependencyProperty.AddOwner MSDN页面提供了一个示例,其中包含两个具有静态成员的类,并且一个类的成员依赖于另一个类的成员进行初始化.我认为MSDN是错误的 - 静态变量的初始化顺序在C#中是不可靠的,就像在C++或其他任何地方一样.我可能错了,因为WPF库本身就是这样编写的,它运行得很好.我错过了什么?C#编译器如何知道安全初始化顺序?
private const string _DefaultIconPath = _IconsPath + "default.ico";
private const string _IconsPath = "Icons/";
Run Code Online (Sandbox Code Playgroud)
这些字符串在运行时的值:
private readonly string _DefaultIconPath = _IconsPath + "default.ico";
private readonly string _IconsPath = "Icons/";
Run Code Online (Sandbox Code Playgroud)
编译时间错误:
A field initializer cannot reference the non-static field, method, or property '_IconsPath'
Run Code Online (Sandbox Code Playgroud)
private static readonly string _DefaultIconPath = _IconsPath + "default.ico";
private static readonly string _IconsPath = "Icons/";
Run Code Online (Sandbox Code Playgroud)
这些字符串在运行时的值:
null)为什么编译器在示例3中抛出编译错误,类似于示例2?
声明的顺序在static readonly字段定义的情况下很重要,但在const字段定义的情况下则不重要.
编辑:
我理解为什么字符串被初始化为那些特定的值.我不明白的是为什么示例2抛出编译错误,强制初始化发生在构造函数而不是变量声明中(这很有意义),但是示例3的行为方式并不相同.抛出相同的编译错误强制在静态构造函数中进行初始化是不是有意义?
private …Run Code Online (Sandbox Code Playgroud) 我写了一个这样的课:
class Singleton
{
private Singleton()
{
Console.WriteLine("Initialized.");
Singleton.num++;
}
public static uint num;
private static Singleton instance = new Singleton();
public static Singleton Instance
{
get { return Singleton.instance; }
private set { }
}
}
Run Code Online (Sandbox Code Playgroud)
在我的主要方法中,如果我这样写:
Console.WriteLine("====================");
Singleton s = Singleton.Instance;
Console.WriteLine("====================");
//Console.WriteLine(Singleton.num);
Run Code Online (Sandbox Code Playgroud)
我有一个输出像:
====================
Initialized.
====================
Run Code Online (Sandbox Code Playgroud)
但如果我取消注释最后一行,我会得到这样的输出:
Initialized.
====================
====================
1
Run Code Online (Sandbox Code Playgroud)
为什么构造函数在第二种情况下的任何进程之前都是墨水?为什么最后一行会影响以前的程序?
正如标题所示,我感兴趣的是静态类在.NET中加载到内存中,尤其是C#.我认为这是类似于这一问题在Java和这个问题有关的静态方法,在加载它使用它的第一次.另外,一旦它在内存中,它会一直存在,直到应用程序终止,或者当垃圾收集器出现清理使用它的类时,它会被清理干净吗?
我意识到静态类使用的少量内存在具有8 + GB RAM标准的计算机世界中并不是非常重要,但了解内部结构总是很有趣.
编辑:
答案让我想要在这个问题上添加更多内容并通过一个例子来澄清.如果我理解正确,在下面的示例中,Contraption.SomeString将首先放在内存中,然后紧跟Contraption.AnotherString,第一次通过循环.
public static class Contraption
{
public static string SomeString = "Some String";
public static string AnotherString = "Another String";
}
public class Processor
{
public void Process(List<SomeClass> items)
{
foreach(var item in items)
{
if(item.Name == Contraption.SomeString)
{
//do something
}
if(item.Name == Contraption.AnotherString)
{
//do something
}
}
}
}
Run Code Online (Sandbox Code Playgroud) 这段代码似乎没有调用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();
}
}
Run Code Online (Sandbox Code Playgroud)
但是,简单地将Main函数修改为如下所示会导致调用构造函数。
static void Main(string[] args)
{
Console.WriteLine("x = " + mixed.x);
Console.WriteLine("y = " + Mixed.y);
Console.ReadLine();
}
Run Code Online (Sandbox Code Playgroud)
这打印:
x = 1
y = 1
Run Code Online (Sandbox Code Playgroud)
为什么简单地将此引用添加到非静态字段会导致构造函数被正确调用?创建对象不应该总是导致调用构造函数,而不管该对象稍后在程序中如何使用?
奇怪的是, …
考虑以下带有两个静态成员变量的类片段:
public static class Foo
{
static string A = GetA(B);
static string B = "required for A";
...
Run Code Online (Sandbox Code Playgroud)
现在,我的理解是,A和B会在第一次访问时初始化。然而,当我执行上面代码片段的完全实现版本(在初始化A之前访问过的代码片段)时,它导致被传递到而不是. 为什么行为不是开始初始化A,然后,当它意识到需要初始化时,初始化,然后返回以完成初始化?BnullGetA()"required for A"BABA
这方面的一般规则是什么?为什么它会这样?我见过其他涉及此问题的问题(When do static Variables get initialized in C#?),但它们没有准确回答这个问题。C#中静态变量初始化顺序是什么?主要讨论它是如何跨类工作的,而不是在单个类中工作(尽管乔恩·斯基特对他的答案进行了补充——“根据大众的要求,当我认为问题是关于类中静态变量的初始化顺序时,这是我最初的答案:....”确实回答了这个问题,它被隐藏在一个更长的答案中)。
第一张图片中使用的记忆工具来自 Rider。据我所知,它显示了托管堆的分配。第二张图显示了 BenchmarkDotNet 的结果。
为什么 Rider 显示已进行分配,但 BenchmarkDotNet 表明未对堆进行分配?
如果我改用下面的代码示例,BenchmarkDotNet 会选择分配:
var i = new int[0];
Run Code Online (Sandbox Code Playgroud)