1

I have C++ code which uses such approach:

#if defined(CONSTANT)
..
// Some code
#else
// Some other code

I was told I can use similar approach in C#-because I need to rewrite this C++ project to C#. But there is one problem. From the documentation I have seen that in C# if I use

#define CONSTANT

this is only visible in the file where it was declared.

But I don't want this. I want this CONSTANT to be visible in all classes? I think one solution is to declare such constants in the Project Settings etc - but here is my first question: In that case do I need to ship some additional file with my DLL? Or these constants will be embedded in DLL?

Finally, to avoid above problems I am thinking about approach of using just public const values in C#. Like

if(Globals.SomeConstant == SOMEVALUE)
// Do this
else
// Do smth else

And then depending on the configuration I will set default values during declaration of Globals.SomeConstant to the value I need, compile the DLL and ship it. Does this sound ok and will it work like this? Will the default values be assigned and read properly inside DLL methods? (will they work like #ifdefs?)

I know I will need to recompile to change the code but that is ok.

  • 2
    You can define global defines in the project properties for that project. Properties>Build>Conditional Compilation Symbols The defined symbols there will not be embedded, the compiled code will follow a different path in the compiler, compilation symbols are "compile time" things, not runtime. The second method you posted is not equivalent to an `#ifdef`, and I'd avoid that approach. – Ron Beyer Oct 07 '15 at 14:05
  • They are just compile time constants, nothing will be embedded in your DLL. – Ivan Stoev Oct 07 '15 at 14:08
  • @RonBeyer: My point is if I define those constants in Project Properties as you mention, do I need to ship anything additionally with my DLL? Or just my DLL will be ok? and depending which symbols I defined in Properties I can use #ifdefs appropriately then? –  Oct 07 '15 at 14:10
  • The DLL will be all you need to send, the code will be compiled differently depending on if the symbol is defined or not. That is an appropriate use of symbols, to define code that is compiled only when that symbol is defined. – Ron Beyer Oct 07 '15 at 14:12
  • @RonBeyer: Ok so I should check Properties->Build etc. ? What is wrong with the public constants approach –  Oct 07 '15 at 14:16
  • Because both sets of code will be compiled into the resulting DLL possibly including code that could be hacked (dev vs prod versions) or testing code you don't want/need to be released. Typically you use symbols to create different versions for different platforms, you don't want incompatible code to be shipped to a platform that doesn't support it. There are a number of reasons, but it boils down to including code you don't want to be included. – Ron Beyer Oct 07 '15 at 14:18
  • Constants in C++ are declared using `const`, not `#if`. This is a C idiom that should be avoided – Panagiotis Kanavos Oct 07 '15 at 14:41
  • @RonBeyer: It is fine to release DLL so that it works only for some platform. Currently it works like this and our DLL is used like this but in C++. So it is ok if in C# it has same behaviour. Any other problems apart from that? Which shall I use #defines or public consts? –  Oct 07 '15 at 14:53
  • Use compilation symbols, avoid global constant variables. – Ron Beyer Oct 07 '15 at 14:55
  • @RonBeyer: Ok but out of curiosity why? Won't they achieve same effect? –  Oct 07 '15 at 14:58
  • No, like I said, compilation symbols conditionally compile code, global variables will only *run* different code, the code is still there. Using compilation symbols, the code is never compiled into the final assembly, and therefore doesn't exist. – Ron Beyer Oct 07 '15 at 15:01
  • @RonBeyer: I was told that "Be aware though: there is no guarantee that the conditional compilation symbol is the same for all projects in your solution. This will hinder reuse of your DLLs by other solutions that want different conditional compilation symbols." - do you know what it means? –  Oct 07 '15 at 18:49
  • Symbols are defined per-project, not per solution. If you were working with a team of developers, one may define `TRACE_CUSTOM` where another may define `TRACE_ALL` (for example). You just need to be aware of the compilation symbols the other projects are using and make sure the proper ones are defined. This is easily handled by use of build configurations. – Ron Beyer Oct 07 '15 at 18:52
  • @RonBeyer: I am beginner in .NET and this is confusing me. What is build configuration? I don't exactly understand the problem. Let one developer define one symbol in his project. Other in her project. What is the problem? My code will behave differently for developer 1, and differently for developer 2 isn't it? –  Oct 07 '15 at 18:56
  • By default you have 2 build configurations, debug and release. You can define other ones, like debug_win32, debug_win64, debug_mono, release_mono, etc. These can all define different compilation symbols, just like on C++ where you can define different build configurations for different platforms. Yes, both projects will behave differently, its just important to note and I wouldn't worry about it until you get much higher level. – Ron Beyer Oct 07 '15 at 18:58
  • @RonBeyer: Let them behave differently, that is my intention anyway right? else why would I separate different code under #ifdefs. If not I will use public const enum - to remove confusion, I think its functionality is mainly similar to #defines –  Oct 07 '15 at 19:04
  • I'm not sure what else I can say to convince you to use `#if symbol`, at this point if you aren't convinced, use whatever you feel comfortable with. – Ron Beyer Oct 07 '15 at 19:08

2 Answers2

2

C# does not a have "preprocessor" in the same way C/C++ have. Nor these #defines are "constants" - they are just "symbols", which you can only query for presence or absence of. They leave no traces in a compiled assembly.

Now, when you compile your assembly with (or without) a #defined symbol, the result can very well be different:

public const int I =
#if FOO_BAR
    42
#else
    43
#endif
;

The conceptual difference between C/C++ and C# when it comes to #defines is that libraries in C/C++ are usually distributed in source form and, when compiled together with your own code, obey global #defines. In C#, on the other hand, third-party code is most often distributed as a compiled assembly. Thus, if you want to change the way the code in this third-party assembly works, you'll have to do this at runtime.

Anton Gogolev
  • 113,561
  • 39
  • 200
  • 288
  • "In C#, on the other hand, third-party code is most often distributed as a compiled assembly. Thus, if you want to change the way the code in this third-party assembly works, you'll have to do this at runtime." -- Can you please explain what you mean here? –  Oct 08 '15 at 12:12
1

If you are using Visual Studio is pretty simple to do preprocessor directives.

  1. Select Project
  2. Properties
  3. Build
  4. On 'Conditional compilation symbols' put your wanted symbol and you should have access in all the assembly

If you are not using Visual Studio just follow this topic.

For learning purpose about preprocessor directives you can go to Tutorialspoint C# website.

To write code in C# using C++ approach you can use the following syntax:

#define Name_Value

#if (Name_value)
{
   //code
}

If this doesn't fit your needs you can go with a configuration file where you can stack in all your key name - value and access them by ConfigurationManger.AppSettings["Key"]

Another way around this is to have a global enum and assign values.

 public enum DemoEnum
 {
     Name = Value
 } 

 if(passedEnum == DemoEnum.Name)
 {
     // code
 }

The solution you gave with the constants is not very flexible, because if your code changes you will have to create new constants and the image gets too blurry.

Using readonly properties you can switch values of 'const' in your approach.

public class Global
{
    public readonly string Name;

    public Global()
    {
        if(condition)
           Name = 10;
        else
           Name = 30;
    }
}

If I forgot an option feel free to comment :)

Community
  • 1
  • 1
Botea Bogdan
  • 192
  • 3
  • 16
  • " The solution you gave with the constants is not very flexible, because if your code changes you will have to create new constants and the image gets too blurry. " - Can you explain what you mean here? I am thinking about public consts because if there is need for recompile this is not problem because current C++ solution works like that too. What do you think? –  Oct 07 '15 at 18:48
  • I was told that "Be aware though: there is no guarantee that the conditional compilation symbol is the same for all projects in your solution. This will hinder reuse of your DLLs by other solutions that want different conditional compilation symbols." - do you know what it means? –  Oct 07 '15 at 18:49
  • I meant a global const enum basically –  Oct 07 '15 at 18:50
  • @user300224 A global enum would work like a charm, but you have to know what value to test, as you pointed out in your question if(Globals.SomeConstant == SOMEVALUE) // Do this else // Do smth else – Botea Bogdan Oct 08 '15 at 07:54
  • Bodgan: Yes, see here please `public const DppConfiguration configuration = DppConfiguration.SOFTWARE_HSM;` - the `DppConfiguration ` - is an enum. And I have given some initial value at declaration as you can see. Will it work ok even if inside DLL? please comment on this. –  Oct 08 '15 at 08:17
  • @user300224 I have tested your code and it seems to be readable enough. I'm not sure I fully understand the sentence 'Will it work ok even if inside DLL?'. You should create a configuration assembly that will have only this configuration consts and enum and reference this to all other assemblies. – Botea Bogdan Oct 08 '15 at 09:17
  • Inside my DLL I will use these public enums. During compile time I will assign default value to this enum depending which configuration I want. then other project will use this DLL –  Oct 08 '15 at 10:04