[英]My C# program does not initialize the Object how I think it has to according to the Object initialization order. Why?
I believe the Object Initialization order of C# goes like this:我相信 C# 的对象初始化顺序是这样的:
Below you see a simple test program and the output it produces when I run it.下面你会看到一个简单的测试程序和它在我运行时产生的输出。
public class UiBase
{
protected static string Something = "Hello";
public UiBase()
{
Console.WriteLine(this.ToString());
}
}
public class Point : UiBase
{
private int X = -1;
private int Y = -1;
static Point()
{
Something = "Bar";
}
public Point(int x, int y)
{
X = x;
Y = y;
}
public override string ToString()
{
return $"Point:{X}/{Y}/{Something}";
}
}
public static class Program{
public static void Main(){
var x = new Point(2,1);
Console.WriteLine(x);
}
on Console:
Point:-1/-1/Bar
Point:2/1/Bar
When I think about how it should happen according to the list above, I believe it should be like this:当我根据上面的列表思考它应该如何发生时,我认为它应该是这样的:
However it does NOT set Something back to Hello which really confuses me.然而,它并没有将Something设置回Hello,这真的让我感到困惑。 So how can I explain this?
那么我该如何解释呢? or is the Object Initialization different from what I stated?
还是对象初始化与我所说的不同?
You call a virtual member ToString()
in base UiBase
class constructor您在基
UiBase
类构造函数中调用虚拟成员ToString()
Console.WriteLine(this.ToString());
It's being called before Point
constructor它在
Point
构造函数之前被调用
public Point(int x, int y)
{
X = x;
Y = y;
}
this
isn't fully initialized yet, you are getting -1
in output. this
还没有完全初始化,您在输出中得到-1
。 Since ToString()
is virtual method, Point.ToString()
is called, per specs由于
ToString()
是虚方法, Point.ToString()
根据规范调用Point.ToString()
The overriding member in the most derived class is called, which might be the original member, if no derived class has overridden the member.
调用最派生类中的覆盖成员,如果没有派生类覆盖该成员,则该成员可能是原始成员。
Static constructor is called automatically before the instance of Point
is created or any static members are referenced (have a look at the static constructors for details)在创建
Point
实例或引用任何静态成员之前自动调用静态构造函数(查看静态构造函数了解详细信息)
static Point()
{
Something = "Bar";
}
It'll overwrite Something
from base class and you get Bar
in output in both cases.它会覆盖来自基类的
Something
,并且在这两种情况下你都会在输出中得到Bar
。 Something
is never set back to Hello
, it's being overwritten only once. Something
永远不会被设置回Hello
,它只会被覆盖一次。
Something
field is entirely specific for UiBase
, there is no copy in Point
class, it's value will be changed everywhere. Something
字段完全特定于UiBase
, Point
类中没有副本,它的值将随处更改。 According to static members根据静态成员
Only one copy of a static member exists, regardless of how many instances of the class are created.
无论创建了多少个类的实例,都只存在一个静态成员的副本。
If you print UiBase.Something
after Console.WriteLine(x);
如果你在
Console.WriteLine(x);
之后打印UiBase.Something
Console.WriteLine(x);
, you'll get Bar
, not the Hello
. ,你会得到
Bar
,而不是Hello
。 There is only one exception, for generic classes, but it's out of scope of your question.对于泛型类,只有一个例外,但这超出了您的问题范围。
In terms of execution order all field initializers run in order from derived class to base, and then all constructors run in order from base to derived (this is correct for instance members).在执行顺序方面,所有字段初始值设定项按从派生类到基类的顺序运行,然后所有构造函数按从基类到派生的顺序运行(这对于实例成员是正确的)。 I've added a steps for all your operations to see the actual order.
我为您的所有操作添加了一个步骤以查看实际订单。
public class UiBase
{
private static int temp = Step("uibase static field init");
public static string Something = "Hello";
private int _temp = Step("uibase instance field init");
public static int Step(string message)
{
Console.WriteLine(message);
return 0;
}
public UiBase()
{
Step("uibase instance ctor");
Console.WriteLine(this.ToString());
}
}
public class Point : UiBase
{
private int _temp = Step("point instance field init");
private int X = -1;
private int Y = -1;
static Point()
{
Step("point static ctor before");
Something = "Bar";
Step("point static ctor after");
}
public Point(int x, int y)
{
Step("point instance ctor");
X = x;
Y = y;
}
public override string ToString()
{
return $"Point:{X}/{Y}/{Something}";
}
}
the output will be the following输出将如下
point static ctor before
uibase static field init
point static ctor after
point instance field init
uibase instance field init
uibase instance ctor
Point:-1/-1/Bar
point instance ctor
Point:2/1/Bar
The Point
static constructor is invoked first (there is no static fields in Point
class), then it'll 'ask' UiBase
init a static fields, because accessing its Something
value (it's set to Hello
), after that Something
is set to Bar
and execution continues to instance initialization (again, Something
never changes anymore) - derived class fields, base class fields, base class constructor and derived class constructor. Point
静态构造函数首先被调用( Point
类中没有静态字段),然后它会“询问” UiBase
初始化一个静态字段,因为访问它的Something
值(它被设置为Hello
),之后Something
被设置为Bar
并继续执行实例初始化(同样, Something
永远不会再改变)-派生类字段、基类字段、基类构造函数和派生类构造函数。
I think, only first 3 lines can be confusing a little bit, but static initialization happens only once and before any instance initialization.我认为,只有前 3 行可能会有点混乱,但静态初始化只发生一次,并且在任何实例初始化之前。 The order of static initialization is determined by compiler based on your actual code.
静态初始化的顺序由编译器根据您的实际代码确定。
Adding a UiBase
static constructor can make the picture more clear actually, in this case UiBase
static members will be initialized before Point
static initialization.添加一个
UiBase
静态构造函数其实可以让画面更加清晰,在这种情况下UiBase
静态成员会在Point
静态初始化之前被初始化。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.