The conditional attribute is described as follows by MSDN.

The attribute Conditional enables the definition of conditional methods. The Conditional attribute indicates a condition by testing a conditional compilation symbol. Calls to a conditional method are either included or omitted depending on whether this symbol is defined at the point of the call. If the symbol is defined, the call is included; otherwise, the call (including evaluation of the parameters of the call) is omitted.

Now that sounds very complicated.

Lets take this little example.

Imports System.Threading

Module Module1

    Private incre As New Incrementing

    Sub Main()
        For i = 0 To 20
            count()
            count2()
        Next
        Console.ReadLine()
    End Sub

    <Conditional("DEBUG")>
    Sub count()
        For i = 1 To 1000
            incre.Add()
        Next
        Console.WriteLine(incre.Read())
    End Sub

    Sub count2()
        For i = 1 To 500
            incre.Add()
        Next
        Console.WriteLine(incre.Read())
    End Sub

    Public Class Incrementing
        Private i As Integer = 0

        Public Sub Add()
            Interlocked.Increment(i)
        End Sub

        Public Function Read() As Integer
            Return i
        End Function
    End Class
End Module```
When you run this in debug mode you will get.

> 1000
  
> 1500
  
> 2500
  
> 3000
  
> 4000
  
> 4500
  
> 5500
  
> 6000
  
> 7000
  
> 7500
  
> 8500
  
> 9000
  
> 10000
  
> 10500
  
> 11500
  
> 12000
  
> 13000
  
> 13500
  
> 14500
  
> 15000
  
> 16000
  
> 16500
  
> 17500
  
> 18000
  
> 19000
  
> 19500
  
> 20500
  
> 21000
  
> 22000
  
> 22500
  
> 23500
  
> 24000
  
> 25000
  
> 25500
  
> 26500
  
> 27000
  
> 28000
  
> 28500
  
> 29500
  
> 30000
  
> 31000
  
> 31500 

But when you run this in Release mode you will get this.

> 500
  
> 1000
  
> 1500
  
> 2000
  
> 2500
  
> 3000
  
> 3500
  
> 4000
  
> 4500
  
> 5000
  
> 5500
  
> 6000
  
> 6500
  
> 7000
  
> 7500
  
> 8000
  
> 8500
  
> 9000
  
> 9500
  
> 10000
  
> 10500 

So the attribute conditional means that the method you tag with the attribute will only run in the mode you tag it for.

So our method count will not run.

It is a much prettier way than writing this.

```vbnet
Imports System.Threading

Module Module1

    Private incre As New Incrementing

    Sub Main()
        For i = 0 To 20
#If debug Then
            count
            count2
#Else
            count2()
#End If
        Next
        Console.ReadLine()
    End Sub

    Sub count()
        For i = 1 To 1000
            incre.Add()
        Next
        Console.WriteLine(incre.Read())
    End Sub

    Sub count2()
        For i = 1 To 500
            incre.Add()
        Next
        Console.WriteLine(incre.Read())
    End Sub

    Public Class Incrementing
        Private i As Integer = 0

        Public Sub Add()
            Interlocked.Increment(i)
        End Sub

        Public Function Read() As Integer
            Return i
        End Function
    End Class
End Module```
But it doesn’t always work.

Look at this code for example.

```vbnet
Imports System.Threading

Module Module1

    Private incre As New Incrementing

    Sub Main()
        For i = 0 To 20
#If debug Then
            Dim t1 As New Thread(AddressOf count)
            t1.isbackground = True
            t1.start
            Dim t2 As New Thread(AddressOf count2)
            t2.isbackground = True
            t2.start
#Else
            Dim t2 As New Thread(AddressOf count2)
            t2.IsBackground = True
            t2.Start()
#End If
        Next
        Console.ReadLine()
    End Sub

    Sub count()
        For i = 1 To 1000
            incre.Add()
        Next
        Console.WriteLine(incre.Read())
    End Sub

    Sub count2()
        For i = 1 To 500
            incre.Add()
        Next
        Console.WriteLine(incre.Read())
    End Sub

    Public Class Incrementing
        Private i As Integer = 0

        Public Sub Add()
            Interlocked.Increment(i)
        End Sub

        Public Function Read() As Integer
            Return i
        End Function
    End Class
End Module```
We could replace that with this.

```vbnet
Imports System.Threading

Module Module1

    Private incre As New Incrementing

    Sub Main()
        For i = 0 To 20
            Dim t1 As New Thread(AddressOf count)
            t1.isbackground = True
            t1.start
            Dim t2 As New Thread(AddressOf count2)
            t2.isbackground = True
            t2.start
        Next
        Console.ReadLine()
    End Sub

    <Conditional("DEBUG")>
    Sub count()
        For i = 1 To 1000
            incre.Add()
        Next
        Console.WriteLine(incre.Read())
    End Sub

    Sub count2()
        For i = 1 To 500
            incre.Add()
        Next
        Console.WriteLine(incre.Read())
    End Sub

    Public Class Incrementing
        Private i As Integer = 0

        Public Sub Add()
            Interlocked.Increment(i)
        End Sub

        Public Function Read() As Integer
            Return i
        End Function
    End Class
End Module```
Looks a little bit better without the #If.

But the conditional method gets executed anyway, and that’s not what I expected it to do. 

Just try it.

I’m not sure if this is by design or not but I think it’s interesting.

Of course at such a time it is always nice if you can ask someone smarter (which is most people) than you why this happens and if it is by design. 

So I asked Lucian Wischik again. And within 5 minutes I got this answer.

> I think what you’re observing is basically this:

```vbnet
Module Module1

    Sub Main()

        test() ' this call is skipped in release builds

 

        Dim x As Action = AddressOf test ' VB: this works in release+debug builds. C#: is a compile-time error in release+debug builds

        x()

    End Sub

 

    <Conditional("DEBUG")>

    Sub test()

        Console.WriteLine("hello")

    End Sub

End Module

It’s sort of elliptically implied from the first MSDN link,

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.

The line “test()” is a call to the method and hence subject to the above paragraph. But the next line is taking-address-of (not subject to the paragraph) and the one after is call to the delegate’s invoke method (also not subject).

I think the VB MSDN page would be improved if it made this clear. (The C# page already makes it clear that you can’t take the address of a method in C# if that method has the conditional attribute). I’ll pass that on to the authors of the page.