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

时间:2012-04-24 06:37:16

标签: c# optimization

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

只需要创建一个继承自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类值的代码,因此它只是内联代码中使用它们的值。我通过要求类中的所有“选项”字段都是易变的来避免这个问题,因此不应用优化,并且它工作正常,但不幸的是volatile关键字在双精度上无效。

我花了很多时间在网上试图寻找解决方法,但没有成功。无论如何要么阻止对字段的优化,要么欺骗编译器/抖动以为它们在运行时被使用?

我还想尽可能减少调用应用程序的责任。

由于

2 个答案:

答案 0 :(得分:1)

我在这里有一份本地副本,其中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);
}

工作正常。我不相信问题是你认为的。

答案 1 :(得分:1)

这是我的猜测:

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

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

更新(自以为是):

Parse在一个单独的线程中运行是非常奇怪的,应该被认为是一个设计缺陷。听起来有人在想“反思很慢,让我们把它放在一个单独的线程中”。