Оптимизирует ли условная компиляция методы, генерирующие входные аргументы? - PullRequest
0 голосов
/ 14 октября 2018

В C # мы можем выполнить условную компиляцию, используя операторы #if / #endif или атрибуты Conditional.Например, следующий код напечатает что-то только для отладочной сборки:

public static void Main(string[] args)
{
    CheckResult();
}

[Conditional("DEBUG")]
private static void CheckResult() 
{ 
    System.Console.WriteLine("everything is fine");
}

Что произойдет, если этот метод CheckResult() принимает аргументы, и мы используем его так?

public static void Main(string[] args)
{
    CheckResult(CalculateSomethingExpensive() == 100);
}

private static int CalculateSomethingExpensive()
{
    result = //some sort of expensive operation here
    return result;
}

[Conditional("DEBUG")]
private static void CheckResult(bool resultIsOK) 
{ 
    System.Console.WriteLine(resultIsOK ? "OK" : "not OK");
}

В этом случае, какие правила компилятора решают, выполняется ли дорогой метод или оптимизирован?Например, гарантированно ли его удаляют, если он не вносит изменений в состояние какого-либо объекта?

Я понимаю, что неопределенность может быть удалена путем явного использования #if, но когда имеется большая кодовая база ссотни Debug.Assert() заявлений, это может стать неприглядным очень быстро.

1 Ответ

0 голосов
/ 14 октября 2018

Итак, с небольшой модификацией, вот что скомпилировано (под Release):

class Program
{
    public static void Main(string[] args)
    {
        CheckResult(CalculateSomethingExpensive() == 100);
    }

    private static int CalculateSomethingExpensive()
    {
        var result = new Random().Next(100);//some sort of expensive operation here
        return result;
    }

    [Conditional("DEBUG")]
    private static void CheckResult(bool resultIsOK)
    {
        System.Console.WriteLine(resultIsOK ? "OK" : "not OK");
    }
}

Что в значительной степени совпадает с вашим примером, за исключением изменения для компиляции.Компиляция и последующий запуск через декомпилятор приводит к следующему:

internal class Program
{
    public Program()
    {
    }

    private static int CalculateSomethingExpensive()
    {
        return (new Random()).Next(100);
    }

    [Conditional("DEBUG")]
    private static void CheckResult(bool resultIsOK)
    {
        Console.WriteLine((resultIsOK ? "OK" : "not OK"));
    }

    public static void Main(string[] args)
    {
    }
}

Вы видите, что единственное отличие состоит в том, что вызов CheckResult удален из Main.Это означает, что полный вызов удален.Даже если у CheckResult или CalculateSomethingExpensive были побочные эффекты, они будут удалены.

Интересно то, что методы все еще присутствуют в скомпилированном выводе, только вызовы удаляются, поэтомуиспользуйте [Conditional(Debug)], чтобы скрыть секреты, используемые при отладке.

...