C# 如何防止C中类字段的优化#

C# 如何防止C中类字段的优化#,c#,optimization,C#,Optimization,我构建了一个抽象类,用于处理我们产品的命令行选项 只需创建一个继承自AbstractOptions的类,用修饰字段填充它,并调用继承的Parse(args)方法,通过反射自动用命令行中的值填充它。在命令行中找不到的值将保留其当前(默认)值 然后,应用程序只需检查选项字段即可获得其值。AbstractOptions类提供了更多的特性,如帮助输出等,但它并不重要 简短示例: public class SignalOptions: AbstractOptions { [Option("-i,

我构建了一个抽象类,用于处理我们产品的命令行选项

只需创建一个继承自AbstractOptions的类,用修饰字段填充它,并调用继承的Parse(args)方法,通过反射自动用命令行中的值填充它。在命令行中找不到的值将保留其当前(默认)值

然后,应用程序只需检查选项字段即可获得其值。AbstractOptions类提供了更多的特性,如帮助输出等,但它并不重要

简短示例:

public class SignalOptions: AbstractOptions
{
    [Option("-i, --iterations", "Number of iterations (0 = infinite).")]
    volatile public int NumberOfIterations;

    [Option("-s, --silent", "Silent mode, only display final results.")]
    volatile public bool Silent;

    [Option("-w, --zwindow", "Window size for z-score analysis.")]
    volatile public int ZWindow = 7;

    [Option("-a, --zalert", "z-score value to consider as peak.")]
    public double ZAlert = 2.1;
}

static void Main(string[] args)
{
    var opts = new SignalOptions();
    opts.Parse(args)

    // If optimizations are turned off, SILENT will be written or not 
    // followind presence or absence of the --silent switch on the command line.
    // If optimizations are turned on, SILENT will never be written.
    // The reflection part is working fine. I suspect the problem is that
    // the compiler of the jitter having never found this set anywhere simply inlines
    // the value 'false' inthe if, because when I step on it, it shows me the value as 
    // true or false, but has the same behavior no matter what value opts.Silence has.
    if( opts.Silent )
        Console.Writeline("SILENT");
}       
现在,我遇到的问题是,由于编译器没有发现任何实际更改SignalOptions类值的代码,它只是将代码中使用的值内联起来。我通过要求类中的所有“option”字段都是volatile来避免这个问题,因此没有应用任何优化,而且效果很好,但不幸的是volatile关键字在double上无效

我花了很多时间在网上试图找到一个解决办法,但没有成功。有没有办法阻止对字段进行优化,或者以其他方式愚弄编译器/抖动,使其认为这些字段是在运行时使用的

我还希望尽可能减少呼叫应用程序的责任


谢谢

我这里有一个本地副本,
Parse
写得相当不透明:

public void Parse(string[] args)
{    // deliberately opaque, not that it would make any difference
    string fieldName = (new string('S', 1) + "ilentX").Substring(0, 6);
    GetType().GetField(fieldName).SetValue(this, true);
}
它很好用。我不相信问题出在你的想象中。

以下是我的猜测:

Parse
在一个单独的线程中运行,但是由于您的同步存在某种缺陷,这使得代码的其余部分在没有设置值的情况下运行

这也解释了为什么在调试器中看到正确的值

更新(固执己见):


Parse
在一个单独的线程中运行是非常奇怪的,应该被认为是一个设计缺陷。听起来好像有人在想‘反射太慢了,让我们把它放在一个单独的线程中吧’

我强烈怀疑您误诊了这个问题。请展示一个简短但完整的程序来演示这个问题。编译器如何知道是否使用了公共类的公共字段?它可以用于不属于当前构建的程序集:
[MethodImpl(methodimpoptions.noinline)]
对字段无效,因此我怀疑这是您的真实代码我非常确定
volatile
没有解决您的问题,只是掩盖了它。显然,您在
opts.Parse
中犯了一些可怕的错误,但是如果没有相关的代码,我们无法告诉您是什么。您的代码(您没有发布的代码!)几乎是错误的。这就是为什么发布所有相关代码很重要的原因。像这样的问题只会浪费每个人的时间。正如我所说,反思很有效。这不是问题所在。问题是,尽管反射值现在设置为预期值,但其余的应用程序代码甚至不会读取该值,当然,除非禁用了优化。@user611710您禁用了哪些优化,具体是如何禁用的?我们需要确切地了解你所看到的。。。但是通过检测从未分配的字段来删除分支不是一件容易的事情。我应该说:我正在使用一个发布版/优化版在调试器内部和外部进行测试。我还没有弄清楚原因,但无法在实际应用程序中重现问题。谢谢大家给我时间。我不知道如何将这个问题标记为过时的、不好的或其他的,所以我检查了这个答案作为被接受的答案。事实上,一个时间问题使得这个问题成为海森堡可能是一个原因——如果没有
解析
,有点难说,但是……好吧,也许我没有正确地解释自己。1) 只有一个线程,它是一个简单的控制台应用程序。2) 如果我使用volatile关键字,在任何情况下都可以正常工作。3) 如果我删除volatile关键字,我需要禁用优化以使其正常工作4)我通过取消选中“项目生成选项”中的“优化代码”复选框来禁用优化。@user611710您能否显示一个完整的示例,实际显示您描述的问题?它不需要使用实际的
Parse
code(请参见我的示例以获取说明)。如果您能展示一个基本的独立示例来说明这一点,我们将全力以赴。我的猜测是,你很难在一个简单的例子中重现这一点,而逐渐/仔细地将这个简单的例子转化为你的真实代码将准确地显示出真正的问题所在。如果应用程序如此简单,只需在这里或在pastebin上发布解析的内容即可。org@user611710另外,请注意,我尝试过使用/不使用优化,以及有/没有
volatile