为什么在 C# 中顺序对于静态初始化很重要?

发布于 2024-07-15 11:00:31 字数 492 浏览 7 评论 0原文

此代码在 C# 中具有明确定义的不工作行为:

class Foo
{
    static List<int> to = new List<int>( from ); // from is still null
    static IEnumerable<int> from = Something();
}

注意:我不是问如何将该代码修复为 我已经知道如何做到这一点

这样做的理由是什么? C# 已经执行运行时检查来检测对静态成员的首次访问。 为什么不将其扩展到每个成员并让它们按需运行,或者更好地让编译器在编译时找出顺序?

顺便说一句:我认为同样的问题(或几乎相同)也适用于非静态成员。

This code has the well defined behavior in C# of not working:

class Foo
{
    static List<int> to = new List<int>( from ); // from is still null
    static IEnumerable<int> from = Something();
}

Note: I'm not asking how to fix that code as I already known how to do that

What is the justification for this? C# already does run time checks to detect the first access to static members. Why not extend this to a per member thing and have them run on demand or even better have the compiler figure out the order at compile time?

BTW: I think the same question (or almost the same) also holds for non static members.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

追风人 2024-07-22 11:00:31

初始化器只是一个语法糖。 编译器在编译您的类时将该代码放入 .cctor 中,并按照它们在代码中的排列顺序放置它们。

它不运行任何检查,因为它没有意义。 您仍然可以有初始化周期,因此无论如何它都不起作用。

如果您有兴趣,我前段时间在博客上介绍过它:

Initializers are just a syntactic sugar. Compiler puts that code in the .cctor when it compiles your class, and it pust them in the orders they're layed out in the code.

It doesn't run any checks, because it wouldn't make sense. You could still have initialization cycles, so it wouldn't work anyway.

I blogged about it some time ago if you're interested:

悍妇囚夫 2024-07-22 11:00:31

我可以想象程序员会由于其他静态类的副作用而依赖于初始化顺序。 你我都知道依赖副作用是不好的做法,但这并不一定是非法的。

考虑这样的事情:

class Foo
{
    static string header = Bar.GetHeader();
    static string version = Bar.GetVersion();
}

并且 Bar.GetVersion 假设 Bar.GetHeader 已被调用。 如果编译器可以随意更改初始化顺序,那么程序员将无法保证初始化顺序。

丑陋,理所当然,但完全合法。 如果您想象二阶效应(即称为静态方法,它们本身依赖于具有副作用的类),您会发现编译器不可能可靠地重新排列任何内容,就像编译器(通常)不可能重新排列静态构造函数中函数调用的顺序。

I can envision a programmer depending on initialization order due to side effects with other static classes. You and I both know that depending on side effects is bad practice, but it's not necessarily illegal.

Consider something like this:

class Foo
{
    static string header = Bar.GetHeader();
    static string version = Bar.GetVersion();
}

And Bar.GetVersion assumes that Bar.GetHeader has been called. If the compiler were free to change the initialization order, then the programmer wouldn't be able to guarantee the initialization order.

Ugly, granted, but perfectly legal. If you imagine second-order effects (i.e. called static methods that themselves depend on classes that have side effects), you see that it's impossible for the compiler to reliably rearrange anything, just as it's impossible (in general) for the compiler to rearrange the order of function calls in your static constructor.

飞烟轻若梦 2024-07-22 11:00:31

C# 执行运行时检查来检测对类的首次访问,但不会重新排序类内的静态初始化。

静态字段从上到下初始化,然后是静态构造函数从上到下初始化。 更改字段的顺序或创建静态构造函数并从其中初始化字段。

请参阅 C# 规范中的 变量初始值设定项 或 < a href="http://www.yoda.arachsys.com/csharp/beforefieldinit.html" rel="nofollow noreferrer">这篇关于初始化器的文章.. 另外,问题 C# 中静态构造函数/初始化程序的顺序 是相关的。

C# does runtime checks to detect the first access to a class, but does not re-order static initialization within a class.

The static fields are initialized from top to bottom followed by the static constructors from top to bottom. Either change the order of your fields or create a static constructor and initialize the fields from tehre.

See Variable initializers in the C# spec or this article on initializers.. Also, the question Order of static constructors/initializers in C# is related.

向日葵 2024-07-22 11:00:31

我认为你需要使用的是静态构造函数。

至于

class Foo
{
    static List<int> to;
    static IEnumerable<int> from;

    static Foo()
    {
        from = Something();
        to = new List<int>(from);
    }
}

为什么 C# 不在第一次访问时执行此操作,我只是不认为当有其他替代方案可以清楚地表明发生了什么时需要这种复杂性。

I think what you need to use is a static constructor.

Like so

class Foo
{
    static List<int> to;
    static IEnumerable<int> from;

    static Foo()
    {
        from = Something();
        to = new List<int>(from);
    }
}

As to why C# doesn't do it on first access, I just don't see the need for that kind of complexity when there are other alternatives that make it clear what's happening.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文