How do I set a conditional compile variable? - c#

In C/C++ you can define macros in code like this:
#define OLD_WAY 1
Although I've never done it, I assume that the same thing is available in C#. More to the point, in C/C++ it is possible to then do some conditional compilation logic by doing something like this:
#if OLD_WAY == 1
int i = 0;
#else
int i = 1;
#endif
OK, so this is all cool and all that. And again, I assume that such logic is possible within C#. What I'd like to know is, how do I define constants at the project level, so that I can put in logic that will allow me to conditional compile one block of code if I define the constant one way, or another block of code if I don't define it that way? I'm assuming that it's done somewhere in the project's properties, but how and where do I define it?

The C# compiler csc.exe and the C# language itself do not expose any predefined constants for conditional compilation. Visual Studio only adds the DEBUG and TRACE values, which can be configured through the IDE. The IDE also lets you add your own arbitrary symbols, but since these are essentially fixed (invariant) values, the capability is of limited use.
More powerful custom options can set up by manually editing your .csproj project file. You can set up conditions here to selectively propagate conditional compilation symbols into C# based on the huge amount of environment and configuration information available in MSBuild (see here and here, but in principle, there can be no complete list, since disparate components arbitrarily contribute metadata ad-hoc).
Let's consider a working example. One case where it's useful to conditionally compile is if you want to write code that adapts to the whatever tools are discovered during the build. This way you can exploit the latest language features while still preserving the ability to compile on machines with older tooling which would, as expected, reject the alien syntax and/or keywords. For the particular case of C# 7.0 in Visual Studio 2017 we can modify the .csproj as follows:
.csproj file (excerpt):
You could also identify each of the older C# compilers as well, degrading gracefully along the way. The same goes for detecting the .NET Framework version (oft-requested on Stack Overflow [1]
[2]
[3]
[4]) and any other ambient build conditions. Such are left as exercises for the reader, but in case you want to copy/paste the highlighted lines from above, here is the text version. As an update over the screenshot, I added single-quotes to the conditional expression here (even though everything seemed to work without them)
<DefineConstants Condition="'$(VisualStudioVersion)'=='15'">CSHARP7</DefineConstants>
<!-- ... -->
<DefineConstants>DEBUG;TRACE;$(DefineConstants)</DefineConstants>
<!-- ... -->
<DefineConstants>TRACE;$(DefineConstants)</DefineConstants>
Anyway, in this manner you can now write conditional C# code using #if… #elif… #else… #endif. Continuing the example case, the code below uses new tuple syntax--only available in C# 7--to swap array elements. Incidentally, the tuple version is not only more concise and/or elegant; it also produces excellent CIL code:
#if CSHARP7
(rg[i], rg[j]) = (rg[j], rg[i]); // Swap elements: tuple syntax
#else
var t = rg[i]; // Swap elements: clunky
rg[i] = rg[j];
rg[j] = t;
#endif
Note that the Visual Studio IDE does correctly process your manual .csproj customizations in every regard. Given the .csproj I showed earlier, the IDE code editor properly recognizes and evaluates conditional compilation for the purposes of IntelliSense, refactoring, "dimming-out" inactive blocks of code, etc.
I also mentioned that MSBuild has a treasure trove of information available, of which $(VisualStudioVersion) was just one example. Unfortunately, there's no easy to find out which values are available and what values they might have at buildtime. A trick is to temporarily put a C++ project into your Visual Studio solution (if you don't already have one) alongside your C# project. If you right click the project properties for this .vcxproj and then look at (e.g.) "Additional Include Directories" on the C/C++ page, a dropdown will appear at the far right when you click to edit:
You'll get a dialog box with a "Macros" button which you can click to get a list of all the available MSBuild variables plus their expected values according to platform and configuration that are currently selected in the IDE. Don't overlook the well-known item metadata fields (prefixed with %) at the bottom of the list.
You can get an idea for how much stuff is here from the size of the scrollbar thumb in this screenshot. (They're listed alphabetically; I just scrolled to this part of the 'P' section, because it had minimal personal information.) It's important to note, however, that both the (available) variables and their values evolve over time during the course of the build, so you may find items in this list that aren't available to your .csproj at the time it's processed.
Another way to find out what property values are available during and throughout your build process is to set the MSBuild "output verbosity" to "Detailed", and then rebuild.
After the build finishes, examine the top of the build log in the Visual Studio Output Window, and you'll see a list of the available property names along with their initial values.

In C# you can do #define, but you can't use values on them like you can in C++. Each define can have two states: defined or undefined
In the project properties under Build you can set defines that should be defined. Anything you specify here will be defined across all of your project files.
So for example I can define two conditional compilation symbols in this field as:
MY_DEFINE1, MY_DEFINE2
Then in my code I can do things like this:
#if MY_DEFINE1
// Do something conditionally
#endif
#if MY_DEFINE2
// Do something else conditionally
#endif
Alternatively you can do your defines per file, but unlike C++ they must be at the top of your file.
At the top of your file you can use:
#define MY_DEFINE2
Or at the top of your file you can use:
#undef MY_DEFINE2
This last one you'd do if you set a conditional compilation symbol and you wanted it in all files except maybe one.

Open your project properties and look at the Build page. There is a box called Conditional compilation symbols:

Related

Is there a way to have multiple versions of an app in one project? [duplicate]

In C/C++ you can define macros in code like this:
#define OLD_WAY 1
Although I've never done it, I assume that the same thing is available in C#. More to the point, in C/C++ it is possible to then do some conditional compilation logic by doing something like this:
#if OLD_WAY == 1
int i = 0;
#else
int i = 1;
#endif
OK, so this is all cool and all that. And again, I assume that such logic is possible within C#. What I'd like to know is, how do I define constants at the project level, so that I can put in logic that will allow me to conditional compile one block of code if I define the constant one way, or another block of code if I don't define it that way? I'm assuming that it's done somewhere in the project's properties, but how and where do I define it?
The C# compiler csc.exe and the C# language itself do not expose any predefined constants for conditional compilation. Visual Studio only adds the DEBUG and TRACE values, which can be configured through the IDE. The IDE also lets you add your own arbitrary symbols, but since these are essentially fixed (invariant) values, the capability is of limited use.
More powerful custom options can set up by manually editing your .csproj project file. You can set up conditions here to selectively propagate conditional compilation symbols into C# based on the huge amount of environment and configuration information available in MSBuild (see here and here, but in principle, there can be no complete list, since disparate components arbitrarily contribute metadata ad-hoc).
Let's consider a working example. One case where it's useful to conditionally compile is if you want to write code that adapts to the whatever tools are discovered during the build. This way you can exploit the latest language features while still preserving the ability to compile on machines with older tooling which would, as expected, reject the alien syntax and/or keywords. For the particular case of C# 7.0 in Visual Studio 2017 we can modify the .csproj as follows:
.csproj file (excerpt):
You could also identify each of the older C# compilers as well, degrading gracefully along the way. The same goes for detecting the .NET Framework version (oft-requested on Stack Overflow [1]
[2]
[3]
[4]) and any other ambient build conditions. Such are left as exercises for the reader, but in case you want to copy/paste the highlighted lines from above, here is the text version. As an update over the screenshot, I added single-quotes to the conditional expression here (even though everything seemed to work without them)
<DefineConstants Condition="'$(VisualStudioVersion)'=='15'">CSHARP7</DefineConstants>
<!-- ... -->
<DefineConstants>DEBUG;TRACE;$(DefineConstants)</DefineConstants>
<!-- ... -->
<DefineConstants>TRACE;$(DefineConstants)</DefineConstants>
Anyway, in this manner you can now write conditional C# code using #if… #elif… #else… #endif. Continuing the example case, the code below uses new tuple syntax--only available in C# 7--to swap array elements. Incidentally, the tuple version is not only more concise and/or elegant; it also produces excellent CIL code:
#if CSHARP7
(rg[i], rg[j]) = (rg[j], rg[i]); // Swap elements: tuple syntax
#else
var t = rg[i]; // Swap elements: clunky
rg[i] = rg[j];
rg[j] = t;
#endif
Note that the Visual Studio IDE does correctly process your manual .csproj customizations in every regard. Given the .csproj I showed earlier, the IDE code editor properly recognizes and evaluates conditional compilation for the purposes of IntelliSense, refactoring, "dimming-out" inactive blocks of code, etc.
I also mentioned that MSBuild has a treasure trove of information available, of which $(VisualStudioVersion) was just one example. Unfortunately, there's no easy to find out which values are available and what values they might have at buildtime. A trick is to temporarily put a C++ project into your Visual Studio solution (if you don't already have one) alongside your C# project. If you right click the project properties for this .vcxproj and then look at (e.g.) "Additional Include Directories" on the C/C++ page, a dropdown will appear at the far right when you click to edit:
You'll get a dialog box with a "Macros" button which you can click to get a list of all the available MSBuild variables plus their expected values according to platform and configuration that are currently selected in the IDE. Don't overlook the well-known item metadata fields (prefixed with %) at the bottom of the list.
You can get an idea for how much stuff is here from the size of the scrollbar thumb in this screenshot. (They're listed alphabetically; I just scrolled to this part of the 'P' section, because it had minimal personal information.) It's important to note, however, that both the (available) variables and their values evolve over time during the course of the build, so you may find items in this list that aren't available to your .csproj at the time it's processed.
Another way to find out what property values are available during and throughout your build process is to set the MSBuild "output verbosity" to "Detailed", and then rebuild.
After the build finishes, examine the top of the build log in the Visual Studio Output Window, and you'll see a list of the available property names along with their initial values.
In C# you can do #define, but you can't use values on them like you can in C++. Each define can have two states: defined or undefined
In the project properties under Build you can set defines that should be defined. Anything you specify here will be defined across all of your project files.
So for example I can define two conditional compilation symbols in this field as:
MY_DEFINE1, MY_DEFINE2
Then in my code I can do things like this:
#if MY_DEFINE1
// Do something conditionally
#endif
#if MY_DEFINE2
// Do something else conditionally
#endif
Alternatively you can do your defines per file, but unlike C++ they must be at the top of your file.
At the top of your file you can use:
#define MY_DEFINE2
Or at the top of your file you can use:
#undef MY_DEFINE2
This last one you'd do if you set a conditional compilation symbol and you wanted it in all files except maybe one.
Open your project properties and look at the Build page. There is a box called Conditional compilation symbols:

Apply Visual Studio Quick Actions and Refactorings across entire C# solution

I am trying to cleanup/refactor a legacy C# solution and am therefore exploring options how certain refactorings or quick actions could be applied for the entire solution.
For example, Visual Studio 2017 offers 'Replace xxx and xxx with property' and 'Use auto-property' actions, which I can apply via the lightbulb icon for individual classes and methods/properties.
How could I apply these to the entire application or semi-automatically iterate all occurrences (300+) and apply these?
I am open for all options - command line, powershell, VBA, even VISX-development.
I do not want to re-develop the refactoring itself and I don't think that a simple find&replace will do either.
When the quick action window is visible, you can apply the selected fix to the single instance, or across the entire document/project/solution:
If you apply each identified fix across your solution (or project) then you should only need to process each suggestion once, as the first one you change will apply to all further instances.
Alternatively, you could use the dotnet Format tool to apply a set of specific formatting rules to your project via the command line, although this depends upon you having an editorConfig file with your rules defined.
Have a look at the EditorConfig. What you're looking for is the Language Conventions topic and you can flag an action as silent (synonym for refactoring in v15.8):
# $slnRoot\.editorconfig
[*.cs]
dotnet_style_prefer_auto_properties = true:silent
Then when you run across that action in your code, you can apply the quick action to your entire solution, file, project, etc.
Note: there have been some bugs with EditorConfig in VS2017. I've had to close the solution and restart the IDE to get changes to take sometimes.

Conflict : 'space Bar' changes to 'tab' when something is edited

I am getting this conflict every now and then, the spaces(....) are shown as a tab(->) when I am changing something in code. I am attaching an image, where I compared my file with the previous one. If anyone encountered with same error please let me know.
Conflict Image:
You can either change to an external comparer, one that can be configured or setup the code formatting in visual studio to adhere to the project formating guidelines whatever they are.
To configure the Visual Studio, just go Tools --> Options --> Text editor --> All languages (or the one you are using) --> Tabs and change the settings to whatever behaviour works for you.
You seem to have the editor tool configured the use tabs instead of spaces.
How you can control this in VS is answered by https://stackoverflow.com/a/51922994/3906760.
There is, however, another way how this could be controled from "the outside". There is editorconfig (you can spot this, if there is an .editorconfig file your repository), then on save the files will be converted automatically. This is also a way, to consistently push the coding rules to other developers.

Can I have global preprocessor definitions in C# library?

In C# you can have conditional compilation by using macros similar to the C/C++ syntax. This would enable the following to happen:
#define MYMACRO
....
#if MYMACRO
//some C# code logic
#else
//some other C# code logic
I need to define some macros in a dedicated file in a C# library project, and I need these macros to be visible inside the entire library, once defined. The problem is that the above code works only for a single file.
Another way I know to work around this, is to add the macros to the build command. This would take care of defining the macros for the entire .dll and I will have the #if - #else checks working wherever I want inside the library. The issues with this approach is that I want to be able to maintain the macros easily. Having them in a file inside the project will be perfect. I'd like to have some comments inside too, so that I will know what each macro is doing. This will not be applicable if I have to pass the macros as build parameters. Another reason is being able to turn a macro on/off by simply commenting it and examining the behavior.
Is there a decent way to achieve my requirement? I'd prefer not to deal with any build automation tools like MSBuild, NAnt or anything like this, still if no other way is possible I'd appreciate an advice which one you consider a better choice.
You #define them for an entire project with Project + Properties, Build tab, "Conditional compilation symbols" setting. This sets the <DefineConstants> element in the project file. You override this property with msbuild by giving it the /property:DefineConstants="MYMACRO" command line option.
I'd also advise putting the macros in the project settings (csproj file) as #Hans Passant suggests.
If you need the defines documented, you could add a documentation file to the solution explaining what the settings mean.
If there aren't too many variants, you could define a new project configuration for each one. That will allow you to pre-configure the necessary list of #defines for each variant, and then simply switch between them from the configuration combo box in the toolbar. If you want to temporarily disable one option, you could duplicate the current configuration and remove the #define, then delete the config later when you've tested it.
The next option I can suggest to make it "easier" (by combining the settings and docs into a single file as you've suggested) would be to use a simple text file (settings + comments) to configure the project, and spend 15 minutes writing a quick c# app to read this file and write the settings it contains into the .csproj file - it's just XML so should be a trivial app to write. You'd be able to easily tweak this file and run your updater app to chnage the project settings. If it's something you will do often, spend 30 minutes on it and add a UI with checkboxes to choose the settings more easily.
The concept you're describing sounds rather odd, though. The point of a library is usually that you have one standardised lump of code that can be shared by many clients, so changing these sort of defines to reconfigure the whole library a lot is not something that I'd expect to need to do very often. Perhaps you have good reasons, but it may be worth reviewing why you need to solve this #define problem.
(e.g. If you have lots of customers who need different variants of the "library", the best approach will be to use configurations (described above) to allow you to build all needed variants in a batch build. If you are just trying out lots of different algorithms/techniques then can you redesign chunks of the library so that you can restrict the impact of most #defines to just to a single .cs file so they no longer need to be global? Perhaps the library shouldn't be in a single dll, or a plug-in architecture is needed to allow you to pick and choose the "modules" that are included within the library)
C# “preprocessor” directives don't work the same as C preprocessor directives. The most important difference for you is that there is no equivalent of #include. It's not needed under normal circumstances, because C# doesn't have (or need) header files. I don't think what you want is possible, unless you somehow create your own preprocessor or read the file with #defines and make them into parameters of msbuild.
But I think it would be easier for you to use more object-oriented approach: encapsulate the different approaches into classes and use them. To specify which one of them to use, you could use dependency injection. That means you would have to ship a DI library along with your library, but I think that's a price worth paying.
Also, this approach would alleviate a problem with conditional compilation: specifying different set of symbols may break the build in unexpected ways.
Using GUI
Open the project in Visual Studio
Right-Click on the project file in the solution explorer go to properties
Go to Build tab and Make sure you select the All Configurations in the configuration drop down
Make sure selected the All Platforms in Platform drop-down
Type the Preprocessor Definitions you want in the Conditional Compilation Symbols text box separated by semicolon
To the Project file
Open the project file in a text editor
Copy and paste this code to end of existing PropertyGroup
<PropertyGroup Condition="'$(VariableName)'=='VarableValue'">
<DefineConstants>PDEF1;PDEF2;PDEF3</DefineConstants>
</PropertyGroup>
If you not required to add a condition, delete the Condition="'$(VariableName)'=='VarableValue'" part
Save the project file and open from Visual Studio
From: https://codeketchup.blogspot.sg/2018/04/how-to-add-project-level-preprocessor.html

How do I remove unnecessary resources from my project?

I am working with a very big project (a solution that contains 16 projects and each project contains about 100 files).
It is written in C++/C# with Visual Studio 2005.
One of the projects has around 2000 resources out of which only 400 are actually used.
How do I remove those unused resources?
I tried to accomplish the task by searching for used ones.
It worked and I was able to build the solution, but it broke at runtime.
I guess because enums are used. (IMPORTANT)
How can I make sure that it doesn't break at runtime?
EDIT:
I think one method could be to generate the resource (that is not found) on the fly at runtime (somehow).
But I have no idea about ... anything.
NOTE: It's okay if a few unnecessary resources are still there.
What I would do is write a custom tool to search your source code.
If you remove a resource ID from a header file (i.e. possibly called resource.h) and then recompile and get no warnings: then that's a good thing.
Here is how I would go about writing the app. Take as input the resource file (resource.h) you want to scrutinize. Open the header file (*.h) and parse all the resource constants (Or at least the onces you are interested in). Store those in a hash table for quick look up later.
For each code file in your project, search the text for instances of each of your resource ID's. When a resource ID is used, increment the value in the hash table otherwise leave it at zero.
At the end, dump all the resource ID's that are zero out a log file or something. Then test that indeed you can remove those specified resource ID's safely. Once you do that, then write another tool that removes the specified resource ID's given the results of your log file.
You could write such a tool in perl and it would execute in about 0.3 seconds: But would take days to debug. :)
Or you could write this in .NET, and it would execute a little slower, but would take you an hour to debug. :)
You can use third party plug-in for Visual Studio as ReSharper. This add-in will analyze your C# code and point out unused resources. But it only works with C#.
For C++ projects, check out The ResOrg from Riverblade.
"The Resource ID Organiser (ResOrg for short) is an Add-in for Visual C++ designed to help overcome one of the most annoying (and unnecessary) chores of developing/maintaining Windows applications - maintaining resource symbol ID values"
http://www.riverblade.co.uk/products/resorg/index.html
I've never had one that bad. My method in compiled programs is to use a REXX script which emulates GREP looking for references to source that I suspect is not being used, remove them from the program and see what breaks. I use the REXX script because I can pre-filter the list of files I want to search. Which allows me to do a search across folders and computers.
If your code contains dynamic loading of resources (e.g. via strings) at runtime, then there is no way to automatically determine which resources can be safely removed from the source. A dynamic loading statement could load any resource.
Your best bet is to start with your trimmed down version of the app, run it, and identify which resources are missing when you test it. Then add them back in and retest.
You may want to take a look at the tool Reflector (free), not to be confused with ReSharper (expensive). It can show you which DLLs are dependent on another. Then if you want you may be able to remove the DLL that is not being referenced by anything else. Watch out if you are using dependency injection or reflection which then could break your code without your knowledge.
Reflector:
http://www.red-gate.com/products/reflector/.
This add-in draws assembly dependency graphs and IL graphs:
http://reflectoraddins.codeplex.com/Wiki/View.aspx?title=Graph.
In the "Resources View" of the Solution Explorer, right-click and select "Resource Symbols". Now you get a list where you can see which resources constants are used in the .RC-file. This help you might be a bit on the way to cleanup your Resource.h (although it does not show you which resources are not used in the actual C++ code).
Maybe Find Unused Resources in a .NET Solution helps here? Basically, you'll have to check which resources are used (e.g. by comprehensive code coverage checks) and remove the unused ones.
And probably you should not be afraid by using the trail-and-error approach to cleaning up.
In the Solution Explorer, right click and on a Reference and click on the menu item Find Dependent Code.
If it can't find any dependent code then you can remove this reference from the project. (The Remove operation is also under the right-click menu.)
EDIT: For a large project, the Find Dependent Code operation will take a long time. So since you have 2000 resources and most likely value your time this probably is not a viable option....
For C++ resources, did you try right-clicking the project in "Resource View" and then deleting the ones which do not have a tick mark next to them? It is unsafe to delete unused dialog resources since they are referenced as "enum"s in code (like the following).
enum { IDD = IDD_ABOUTBOX };
..however for all the others it should be safe.

Categories

Resources