Is it possible in C# to set such a condition that if the condition is true - compile one file; if the condition is false - compile another file?
Sort of like
#ifdef DEBUG
#include Class1.cs
#else
#include Class2.cs
#endif
Or possibly set it up in project properties.
No, it isn't.
However, you can wrap both entire files in #if blocks.
You might also want to look at the [Conditional] attribute.
I wouldn't recommend it. I don't like the idea of Debug and Release having such wildly different code that you need to have two totally separate files to make sense of the differences. #if DEBUG at all is a pretty big code smell IMO...
However, you could do it like this:
// Class1.cs
#if DEBUG
...
#endif
.
// Class2.cs
#if !DEBUG
...
#endif
In C# we don't use an include of a file, but you can use conditional methods.
For instance, if I'm developing a game and I'm using a shared code base for my input class, but I want to have one method called if I'm on an Xbox, and a different method get called if I'm on a Zune. It's still going to return the same class of input data, but it's going to take a very different route to get it.
You learn more about conditional methods here:
http://msdn.microsoft.com/en-us/library/aa288458(v=VS.71).aspx
Thankfully no, not in the preprocessor like that. You can, however, exclude the implementation of a whole file within the file itself. Or you can set up a build process with MSBuild or NAnt to switch around our files.
Related
I have an application which I want to create a demo for it. I prefer to give another exe for my paid version and different one for demo to prevent people with demo version to crack my paid version. For now I have commented the code I need in demo so whenever I have to create a demo I go over these comments and make the necessary changes. Today I realize the #if directive..
Now my question is if I have a code like this
#if DEMO
public string test()
{
return "blabla";
}
#endif
and I did not define DEMO directive, so my code gets greyed out obviously and I can't reach this method which is what I was expecting so far. Now I have rebuild my project without defining DEMO directive and I deleted my .pdb file from output folder after that I tried to check my executable with dotpeek and I could not see this test method there.
Can I use this approach to separate my demo and paid version executables? Lets say this test method is a demo method so it wont be seen in paid version if someone cracks it. And same goes for opposite, if this test method is a paid version method and I put it inside #if !DEMO then if I define DEMO and rebuild my exe I won't see this test method there right?
As I mention before I already checked the code and could not see my methods with dotpeek but I just want to be 100% sure that these methods wont seen in programs like dotpeek or anywhere else
Yes, the code is completely omitted if the symbol isn't defined. It can be absolute garbage code - the compiler ignores it completely; it just looks for the end (either #endif or #else).
The question about whether that suits your needs for demo/paid versions is somewhat different, but the answer from the technical perspective of "what gets included in the output" is simple.
I use a log property in my class that is intended only for debugging purposes.
Note: I do not use any existing logger packet, as I manage a large lists of objects each of them having its own (!) log.
As it is not used in release mode, it is enclosed by a preprocessor directive:
#if DEBUG
public List<LogItem> DebugLog { get; }
#endif
Unfortunately, I need to initialize and copy this property a few times, leading to messy code like this:
public MyClass(object parameterA, object parameterB, ...,
#if DEBUG
, List<LogItem> debugLog
#endif
) {
throw new NotImplementedException();
}
Whilst for actual logging, I wrote a [Conditional("DEBUG")] method, I am not aware of any possibility avoiding this ugly and idiom-violating directives for noting arguments and parameters. The ConditionalAttribute appears to be only applicable on properties and attributes.
I am wondering whether there is any design pattern for this problem enabling a better readability. I am looking forward to your ideas!
Have a look at log4net, which is probably the most popular open-source logger for .NET. One of the many benefits you'll see is that you can configure the logger once, in your config file, and have different configurations for debug and release. That way, switching to release is done automatically when you publish the web site or app, you don't have conditional directives in your code, and you don't need to change the code to account for different situations.
In my csharp code I need to define a constant where its value is set from environment variable expansion during compile time.
In this example let's talk about any arbitrary string, such as "Hello World".
For c++ there seem to be various approaches. See the following answer, for example: https://stackoverflow.com/a/22828929
Surprisingly I wasn't able to find a similar solution for csharp.
In particular, there seems to be no way to tweak the "*.csproj" file accordingly?
PS:
As mentioned in the answer by Hans Passant below: there is some logic for "DefineConstants", but they only give you some kind of boolean flag, so you can use it for conditional statements such as "#if TESTFOO" in your source code. you will not be able to use the actual value of the environment variable.
One possible "workaround" (to dynamically generate additional source files) is described in the following answer, for example: https://stackoverflow.com/a/4453285
But I'm still looking for an official solution that is more "straight".
The C# build system does not support using environment variables strongly. Somewhat inevitable in C++ builds, its build model dates from the 1970s, but given a pass by Microsoft for C#. It does have a fantastic knack for causing build breaks when you try to rebuild your app a year or more after having finished the project. Or quickly when you try to build on another machine and its environment isn't set correctly. Having all the build config in one place is the superior solution.
But MSBuild supports them, you can refer to an environment variable with $(NAME) in the .csproj file. You can for example set a conditional compilation symbol with it, the kind you test in an #if expression. That requires editing the .csproj file by hand, use a text editor like Notepad. Locate the <DefineConstants> element, there are normally two. One for the Debug build and another for the Release build. A silly example:
<DefineConstants>DEBUG;TRACE;$(USERNAME)</DefineConstants>
And used like:
static void Main(string[] args) {
#if hpassant
Console.WriteLine("It's mine!");
#endif
Console.ReadLine();
}
Oops, testing it a bit more reveals that it also works fine from the IDE :) Project + Properties, Build tab, Conditional compilation symbols = $(USERNAME). Nice.
C# does not support preprocessor macros. The only way to generate/modify source code before the compiler sees it (that is what you want to do) are template/macro expansion engines (like mustache or t4)
What is the purpose and good usage of #define directive in C#?
There are already few questions on this topic but no answer I need. They only give examples how it works. But I need deeper explanation: why does it exist and what are good ways of using it (if any).
Basically I know how to use it, but for me the usage looks odd. Let's look at example:
#define DEV
#if DEV
Console.WriteLine("Development trace log message");
#endif
For me this is completely different from using #if conditional build with project-defined conditional compilation symbols. If we use project-defined symbol, it is attached to project build configuration and we can manage code needed to build (and excluded from build) with build configuration used. So code
#if DEBUG
Console.WriteLine("Debug log message");
#endif
is fine for me. But as I said it is completely different from using #define directive because it is managable.
Am I correct that 1st example can be managed only manually commenting/uncommenting #define line on every build? If yes, it is not managable, hard-to-maintain and I think this usage of #define is extreemely bad practice and sholdn't exists in the language at all.
I can imagine usage of #define/#undef inside #if statement. Something like
#if DEBUG
#if CLIENT1
#define TEST_CLIENT1
#endif
#endif
#if TEST_CLIENT1
connectionString = "Some specific test connection" //I know this is bad practice even in conditional. Only for example purpose.
#elif
//Read connection from config
#endif
#if UNITTESTS
#undef TEST_CLIENT1
#endif
#if TEST_CLIENT1
Console.WriteLine("Some message");
#endif
Sorry for so complicated example, but that is at least something I can find useful. Though I wouldn't write such code in any way =).
Is there any good usage of #define?
PS: I never used #define myself for 5 years and had no will to do it, but I got a support project which has many strange defines which even named in an odd way. Those defines usually placed at the top of the file, like in my 1st example here. And I have no idea how to maintain this code.
I can't see any valid reason for it other than without it, the #IF statement wouldn't exist.
When you define project level precondition variables using the /define directive on the compiler all it really does is add a #DEFINE to the code.
I would argue that this makes it manageable but not in setting it manually in the code, using the /define statement.
The other usefulness is readability and scope. Project defined statements apply to the project, #DEFINE level statements only apply to one file. This helps keep things organised, readable and stops variable issues.
'#define' is there because people expect it to be there. :) For your purposes (e.g. a large project) it may make more sense to keep preprocessor symbols in your project. For quick debugging or other purposes #define may be the best choice. Additionally, #define allows fine-grained (file level) control of symbols.
Imagine you have a large codebase and a single module that is giving you trouble. You might wish to '#define TRACE' or '#define DEBUG' only in the single file where you want to enable tracing/debugging for performance reasons.
Having recently learned of the DebuggerDisplay attribute, I've found it quite useful. However, one thing that surprises me is that it doesn't have a [ConditionalAttribute("DEBUG")] attribute attached to it. Is there some way to force this or is it a bad idea to try? Or does it not matter for some other reason?
The [ConditionalAttribute("DEBUG")] is only used for optimising out method calls.
If you really want to remove these from your builds you can use #ifdef so that the code is only compiled in release mode.
One thing to bear in mind is that you can still debug binaries in release mode, as long as you have the pdb files it shouldn't matter. Release mode just clears up variables sooner and applies some compiler optimisations
As I often have to debug things in Release configuration builds that don't have the DEBUG directive, I would not want these hints to the debugger to be removed.
However, if you have some proprietary or confidential information in the way you display things when debugging that you don't want to make it into your release build, you may want to consider using the ConditionalAttribute or #if/#elif/#endif preprocessor directives to control what is emitted into your release builds.
For example, you could do:
#if DEBUG
[DebuggerDisplay...]
#endif
public class MyAwesomeClass
{
}
This would ensure the attribute is only emitted when the DEBUG directive is given.
I'll share a pattern that I've come to appreciate using partial.
public partial class MyClass{
//class details here
}
And then elsewhere:
#if DEBUG
[DebuggerDisplay("DebuggerValue")]
public partial class MyClass{
//anything needed for debugging purporses
}
#endif
This gives the ability to use DebuggerDisplay or other attributes without cluttering-up the base class.
I've been using a handful of files, all wrapped in #if DEBUG to hold these Debug-Partials. It helps keep the core classes cleaner and I don't have to remember to start/end compiler directives for each attribute.
I would think it would be a bad idea, because a lot of times the thing you're attaching the attribute to has some other use besides just showing it in the debugger, IMO.