Почему условный атрибут .NET вызывает удаление побочных эффектов? - PullRequest
3 голосов
/ 04 января 2009

Сегодня я прочитал об атрибуте Conditional. По данным MSDN:

Применение ConditionalAttribute к методу указывает компиляторам, что вызов метода не должен компилироваться в промежуточный язык Microsoft (MSIL), если не определен условный символ компиляции, связанный с ConditionalAttribute.

OK. Это понятно Поэтому вызов метода не будет скомпилирован. Но как насчет побочных эффектов?

[Conditional("UndefinedCondition")]
static void f1(int x) { Console.WriteLine(x); }

static int a = 0;
static void f2() { f1(++a); }

Поэтому, когда вызывается f2, вызов на f1 должен быть удален. Но почему удаляется также ++a? Это не имеет никакого смысла для меня!

Ответы [ 4 ]

5 голосов
/ 04 января 2009

Расширяя ответ Марка.

Это определенно "По замыслу". Лучший способ понять рационализацию этого - подумать о том, что заменил этот код. Эта функция во многих и намного более чистых путях идет по пути условно скомпилированного кода.

Например,

#if DEBUG
f1(++a);
#endif

Или другая версия

#define f1(x) ...

В не отладочном случае явно нет побочных эффектов. Это то же самое поведение для [условного] кода. Я согласен, что это не так ясно, как в первом примере, но так же ясно, как и во втором.

5 голосов
/ 04 января 2009

Да, любые вызовы, необходимые для аргументов, также удаляются. Это означает, что для типичного варианта использования (отладочные сборки) вы удаляете все выражение, как правило, то, что предназначено.

По сути, вы должны быть очень осторожны при использовании либо [Conditional] методов, или в равной степени (в C # 3.0) частичных методов - которые ведут себя очень похоже, если другая половина частичного метода не реализован. В качестве примера (для частичных методов) см. Ниже. Обратите внимание, что вызов HasSideEffect() удален (раскомментируйте вторую половину Bar, чтобы он заработал):

using System;
partial class Foo {
    partial void Bar(string value);
    static void Main() {
        Foo foo = new Foo();
        foo.Bar(HasSideEffect());
    }
    static string HasSideEffect() {
        Console.WriteLine("hello");
        return "world";
    }
}

partial class Foo {
    /* uncomment this
    partial void Bar(string value) {
        Console.WriteLine(value);
    }*/ 
}
1 голос
/ 04 января 2009

Я также подозреваю, что это поведение аналогично макросам препроцессора C, которые обычно устанавливаются так, чтобы не оценивать аргументы, когда они не используются.

1 голос
/ 04 января 2009

Полагаю, это связано с простотой реализации компилятора.

Я бы в любом случае боялся такого кода (даже если он работал так, как вы ожидаете) и написал бы как

++a;
f1(a);

для ясности. Вы всегда можете увидеть, что выполнено, а что нет.

...