14

I know that I can use preprocessor directives in C# to enable/disable compilation of some part of code.

If I define a directive in the same file, it works fine:

#define LINQ_ENABLED
using System;
using System.Collections.Generic;

#if  LINQ_ENABLED
using System.Linq;      
#endif

Now, I'm used in C++ at putting all this configuration directives inside a single header file, and include it in all files where I need such directives.

If I do the same in C# something doesn't work:

//Config.cs
#define LINQ_ENABLED

//MyClass.cs
#define LINQ_ENABLED
using System;
using System.Collections.Generic;

#if  LINQ_ENABLED
using System.Linq;      
#endif

I also tried the following but seems that I can't define a directive inside a namespace:

//Config.cs
namespace Conf{
#define LINQ_ENABLED
}

//MyClass.cs
#define LINQ_ENABLED
using System;
using System.Collections.Generic;
using Conf;
#if  LINQ_ENABLED
using System.Linq;      
#endif
  1. What am I doing wrong?
  2. What's the right way of using preprocessor across different files in C#?
  3. Is there any better way to do that?
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Heisenbug
  • 38,762
  • 28
  • 132
  • 190

5 Answers5

14

In your .csproj there is a section:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <DefineConstants>TRACE;DEBUG;LINQ</DefineConstants>
  </PropertyGroup>
</Project>

If you want extra preprocessors you can add them there.

Or via the properties of the project which will add them there automatically for you. In properties under the Build tab.

SynerCoder
  • 12,493
  • 4
  • 47
  • 78
  • Thanks for the answer, could you have a look at Tigran answer too?I prefer that not used dll were not linked too. Is this possible? – Heisenbug Dec 12 '12 at 09:33
  • Not in one project out of the bow as far as I know, but you could make your own program which checks what constants are defined in a project and then unlinks certain libraries if they are not used. Then run that program in a pre-build command. – SynerCoder Dec 12 '12 at 09:46
  • How to add #if #endif across all files @SynerCoder ? – ManirajSS Jul 24 '18 at 07:34
  • @ManirajSS you don't. You use the csproj file to define the constants – SynerCoder Jul 24 '18 at 07:38
  • @SynerCoder I want to target both .net core 2.0 and net40 in only one file. All other files have to work on .net core 2.0. I am trying to avoid #if #endif in other files except that one multiframework file – ManirajSS Jul 24 '18 at 07:42
  • @ManirajSS then use if endif in only that one file – SynerCoder Jul 24 '18 at 11:40
4

You can do it for the entire project from Project|Properties.

Afaik there is no way to use include files in C# so for groups of files there is no easy solution.

H H
  • 263,252
  • 30
  • 330
  • 514
3

Instead of adding conditional compilation to your files, and adding blocks of code which use Linq, and others, which don't. I'd moved all data-access logic (i.e. code which have two implementations - with Linq and without) to separate libraries.

E.g. create interfaces, which your main application will use. And create two implementations of those interfaces - one which use Linq, and another which don't use:

In main project:

public interface IUserRepository
{
    IEnumerable<User> GetUsersByCompanyName(string companyName);
}

In Persistence.Linq.dll :

using System.Linq; 

public class UserRepository : IUserRepository
{
    public IEnumerable<User> GetUsersByCompanyName(string companyName)
    // use Linq here
}

In Persistence.SomethingOther.dll:

public class UserRepository : IUserRepository
{
    public IEnumerable<User> GetUsersByCompanyName(string companyName)
    // do not use Linq here
}

Now you can inject any implementation of IUserRepository into your main application classes.

Sergey Berezovskiy
  • 232,247
  • 41
  • 429
  • 459
  • thanks for your answer too. But I haven't posted the code of my class. Actually it should be a static class which uses extension methods, so I don't think interfaces and DI can be used in this case. – Heisenbug Dec 12 '12 at 09:49
  • @Heisenbug anyway, I try to follow the principle *encapsulate* what varies. You can create two classes with extensions, also you still can use composition with static class. – Sergey Berezovskiy Dec 12 '12 at 10:07
2

There is no sense of applying #define on usings, as in this way you don't unlink from your project the libraries, that I suppose, you would like to avoid to reference in some condition.

There is no such thing in .NET as conditional assemblies reference (if not done manually, dynamically).

So the main point of use of preprocessor directives is just enable/disable parts of the code inside namespaces.

paulroho
  • 1,234
  • 1
  • 11
  • 27
Tigran
  • 61,654
  • 8
  • 86
  • 123
  • Yes I have to do exactly this. I can't using Linq in some context (es. Unity3D compiling against flash) and I of course prefer to unlink the unused import too. – Heisenbug Dec 12 '12 at 09:32
  • If you think about something dynamic I would suggest lookin on some DI (Dependency Injection) frameworks out there, available also for .NET. For a list of those can have a look on: [DI Frameworks list](http://stackoverflow.com/questions/4581791/how-do-the-major-c-sharp-di-ioc-frameworks-compare) – Tigran Dec 12 '12 at 09:34
  • Quite right, an `#if` block around usings makes little sense. I missed that initially. – H H Dec 12 '12 at 09:37
-1

Open project property, then select Build, In General section there is an entry Conditional compilations symbols, in that field add your define symbols

enter image description here

Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77