Sid*_*eus 0 .net c# initialization
我相信 C# 的对象初始化顺序是这样的:
下面你会看到一个简单的测试程序和它在我运行时产生的输出。
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
Run Code Online (Sandbox Code Playgroud)
当我根据上面的列表思考它应该如何发生时,我认为它应该是这样的:
然而,它并没有将Something设置回Hello,这真的让我感到困惑。那么我该如何解释呢?还是对象初始化与我所说的不同?
您ToString()在基UiBase类构造函数中调用虚拟成员
Console.WriteLine(this.ToString());
Run Code Online (Sandbox Code Playgroud)
它在Point构造函数之前被调用
public Point(int x, int y)
{
X = x;
Y = y;
}
Run Code Online (Sandbox Code Playgroud)
this尚未完全初始化,您正在进入-1输出。由于ToString()是虚方法Point.ToString(),根据规范被调用
调用最派生类中的覆盖成员,如果没有派生类覆盖该成员,则该成员可能是原始成员。
在Point创建的实例或引用任何静态成员之前自动调用静态构造函数(有关详细信息,请查看静态构造函数)
static Point()
{
Something = "Bar";
}
Run Code Online (Sandbox Code Playgroud)
它将Something从基类覆盖,并且您Bar在两种情况下都会获得输出。Something永远不会设置回Hello,它只会被覆盖一次。
Something字段完全特定于UiBase,Point类中没有副本,它的值将随处更改。根据静态成员
无论创建了多少个类的实例,都只存在一个静态成员的副本。
如果您UiBase.Something在 之后打印Console.WriteLine(x);,您将得到Bar,而不是Hello。对于泛型类,只有一个例外,但这超出了您的问题范围。
在执行顺序方面,所有字段初始值设定项按从派生类到基类的顺序运行,然后所有构造函数按从基类到派生的顺序运行(这对于实例成员是正确的)。我为您的所有操作添加了一个步骤以查看实际订单。
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}";
}
}
Run Code Online (Sandbox Code Playgroud)
输出将如下
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
Run Code Online (Sandbox Code Playgroud)
在Point静态构造函数首先调用(代码中没有静态字段Point类),那么它会“问”UiBase初始化一个静态字段,因为访问它的Something值(它被设置为Hello),那之后Something被设置为Bar和执行继续实例初始化(再一次,Something永远不再改变) - 派生类字段、基类字段、基类构造函数和派生类构造函数。
我认为,只有前 3 行可能会有点混乱,但静态初始化只发生一次,并且在任何实例初始化之前。静态初始化的顺序由编译器根据您的实际代码确定。
添加UiBase静态构造函数实际上可以使图片更加清晰,在这种情况下,UiBase静态成员将在Point静态初始化之前进行初始化。
| 归档时间: |
|
| 查看次数: |
107 次 |
| 最近记录: |