Actually there are a lot of differences. ConditionalAttribute looks cleaner in code but it has a lot of limitations and at least one advantage over #if.
#if completely removes code from compilation if symbol is not defined.
#if gives you better control over granularity - you can surround one line inside a method or whole method or certain members of a class of even whole class.
#if allows you to write complex conditions like this:
#if DEBUG & !NO_NETWORK
#if has #else and #elif to allow more complex scenarios.
[Conditional] is only applicable to a single whole method returning void.
[Conditional] includes code into compiled assembly but removes all calls to it. If somebody references your assembly, he would see methods marked with [Conditional] and would be able to use them - this is something you can't achieve with #if.
It's interesting to open .Net Framework assemblies with reflector, find methods marked as Conditional["DBG"] and see their usage. None of them, even internal ones, are used anywhere! That's because Microsoft compiled .Net for release without symbol "DBG" defined but they were actually using those methods to debug .Net during development.
- It's not possible to have two method with the same signatures marked with [Conditional] but you can achieve it with #if.
As a last note I must say that conditional compilation sometimes plays evil games when you get completely different behavior in debug and release versions and you only find out about it after you deploy your code and users start complaining. So as a rule of thumb, try to avoid changing behavior with #if, use it only to change input data.
Here's an example of using #if - different application configuration for debug and release versions.
static string ConnectionString
{
#if DEBUG
get { return "<debug connection string>"; }
#else
get { return "<release connection string>"; }
#endif
}