Question

I read about the Conditional attribute today. According to MSDN:

Applying ConditionalAttribute to a method indicates to compilers that a call to the method should not be compiled into Microsoft intermediate language (MSIL) unless the conditional compilation symbol that is associated with ConditionalAttribute is defined.

OK. That's clear. So the call to the method will not be compiled. But what about side effects?

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

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

So when f2 is called, the call to f1 should be removed. But why is ++a removed as well? This does't make any sense to me!

Was it helpful?

Solution

Expanding on Marc's answer.

This is definitely "By Design". The best way to understand the rationalization for this is to think about what this code took the place of. This feature in many, and much cleaner ways, takes the way of conditionally compiled code.

For example,

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

Or another version

#define f1(x) ...

In the non-debug case there are clearly no side effects. This is same behavior for [Conditional] code. I agree it's definitely not as clear as the first example, but it is as clear as the second one.

OTHER TIPS

Yes, any calls required for arguments are removed too. This means that for the typical use-case (debug builds) you remove the entire expression, which is usually what is intended.

Basically, you need to be very careful when using either [Conditional] methods, or equally (in C# 3.0) partial methods - which have very similar behaviour if the other half of the partial method isn't implemented. As an example (for partial methods), see below. Note that the call to HasSideEffect() is removed (uncomment the other half of Bar to see it work):

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);
    }*/ 
}

I guess that's due to ease of compiler implementation.

I would be fearful of such code anyways (even if it worked as you expect it) and write it as

++a;
f1(a);

for clarity. You can always see what is executed and what isn't.

I also suspect that this behaviour is designed to be the same as C preprocessor macros, which typically are set up to not evaluate the arguments when not in use.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top