C# 如何捕获或标记静态字段初始化顺序引起的潜在问题
考虑以下C#代码: 今天早些时候,我编写了一些类似这样的代码,并希望C# 如何捕获或标记静态字段初始化顺序引起的潜在问题,c#,visual-studio-2010,C#,Visual Studio 2010,考虑以下C#代码: 今天早些时候,我编写了一些类似这样的代码,并希望string2包含值AAABBB,但它只包含AAA。我读了一些关于静态变量初始化顺序的书,但对我来说似乎更可取的是,在编译过程中会生成某种类型的警告或错误 两个问题: 为什么允许这样的代码成功编译?(如果答案是:“因为C#spec就是这样写的”,那么为什么它是这样写的?有什么原因我不知道为什么它不总是抛出编译时错误吗?) 如果我以后无意中再次编写此类代码,有没有办法得到编译时警告或其他类型的标志 至于#1:允许代码编译的原因是,
string2
包含值AAABBB
,但它只包含AAA
。我读了一些关于静态变量初始化顺序的书,但对我来说似乎更可取的是,在编译过程中会生成某种类型的警告或错误
两个问题:
string2
变量被明确地初始化为“AAA”+null
。你至少应该得到一个警告,这是有争议的。。。至于你的IDE为什么不警告你,我不知道
关于#2:我不知道。这似乎是一个更合适的问题,如果同时使用IDE标记的话
类的静态字段变量初始值设定项对应于
按中的文本顺序执行的赋值序列
它们出现在类声明中
C#有一个明确赋值
策略,这意味着,例如,字段会自动初始化。因此,您的string3
会自动初始化为null
,因此,就编译器而言,它已经有了值
这意味着string2
的输出是string1+null
(这只是string2
),因此编译器没有理由抛出任何错误(尽管我确实看到了警告的作用)。对于问题2:
像ReSharper这样的工具可以捕捉这些东西。VisualStudio内部可能有一个设置,您可以打开该设置以获得更详细的编译输出
以下是整形器清理后生成“AAABBB”的代码
作为旁注,我要说的是,由于我们通常从上到下阅读,初始化的方式与C#规范10.4.5.1中描述的方式相同似乎是合乎逻辑的。如果您认为静态初始值设定项在逻辑上是静态构造函数的一部分,那么事情就更有意义了。就你而言,就好像你写过:
private static string String1;
private static string String2;
private static string String3;
static Program()
{
String1 = "AAA";
String2 = String1 + String3;
String3 = "BBB";
}
静态初始值设定项不能按您想要的方式工作的原因是,在一般情况下,编译器不可能重新排序。在这种情况下,以及在许多其他情况下,它都可能发生。但是如果你考虑我在我提到的二阶效应,编译器就不能可靠地重新排序任何东西。
如果编译器“有时”进行重新排序,那将非常混乱。*me认为*实际上不可能导致
“AAA”
。。。复制/粘贴,运行…哦,哇,真的!当我投票时,头脑发昏,希望Skeet或Lippert会回答这个问题。如果这是一个问题,不要在声明时初始化,而是在执行赋值的地方运行静态构造函数。ReSharper对此给出了警告。@spender如果我知道的话,这不是问题。问题是,如果我无意中编写了此类代码,并且没有任何东西警告/标记我,并且相关的引用:17.4.5:在默认值状态下,可能会观察到带有变量初始值设定项的静态字段。但是,从风格的角度来看,这是非常不鼓励的。我想知道Visual Studio是否确实有一个设置来捕捉/标记这一点,因为我工作的地方没有R#。我同意从上到下进行初始化的“逻辑性”。但是,如果这些字段不是静态的,编译器就会抛出一个错误。对我来说,这似乎更符合逻辑。@RSW-是的,但要得到这种推理,C#设计团队的人必须回答:)我刚刚通过VS2012 Premium进行了代码分析,但没有任何警告。谢谢你的回答。它确实提供了对事物如何运作的洞察。然而,我好奇的是,为什么编译器允许这样的场景溜走。为什么它不至少用一个警告来标记呢?是否有需要这种灵活性的用例,以至于编译器乐于让它们溜走?在我看来,由于C#spec强烈反对这种用法,大多数在野外使用这种行为都是无意的,就像我的情况一样。@RSW:Eric Lippert,以前是C#开发团队的成员,在博客中谈到了警告的利弊。我怀疑编译器团队认为这还不足以证明警告的合理性。请参阅,了解一些相关的案例。Lippert还链接到解释用于决定什么应该产生警告的决策过程。我提议的场景通过了他的前四个标准,但在后两个标准上可能失败,即:(5)“另一个工具能产生警告吗?”,在这种情况下,R#能,和(6)“用户在测试后会立即发现错误吗?”,这是有争议的。我想知道C#团队是否真的考虑过这个问题并拒绝了它。如果string1
、string2
、和string3
不是静态的,编译器根本不会让这个代码编译。但由于它们是静态的,所以它可以毫无问题地运行。如果是故意的,那么我的问题是“为什么会有不同”?原因是
class Program
{
private const string String1 = "AAA";
private const string String2 = String1 + String3;
private const string String3 = "BBB";
static void Main()
{
Console.WriteLine(String2);
Console.ReadLine();
}
}
private static string String1;
private static string String2;
private static string String3;
static Program()
{
String1 = "AAA";
String2 = String1 + String3;
String3 = "BBB";
}