Changing Conditional Compilation in project reference in Visual Studio - c#

I have a class library A that is used in other projects in my solution like B and C.
Class library A behaves differently based on the presence of a pre-processor directive, for example :
#if some_directive
// some code
#else
// some other code
#end
How can I use class library A in project B with enabled some_directive but use in project C with disabled some_directive?

You can do something like this using the ConditionalAttribute
This is how Debug.WriteLine() is present or non-present depending on presence of the "DEBUG" symbol.
You will be able to define your own name for the conditional symbol that you use to control the presence or absence of the code.
You can then put that symbol into the list in the "Conditional compilation symbols" settings on the project properties "Build" tab for the project where you want the code.
This doesn't allow you to have the "some other code" part unfortunately, and also it only applies to entire methods.

It seems that currently this feature is not supported. According to this post:
The language doesn't support the notion of references via preprocessor
macros.
What you can do is use a msbuild file and alter the set of references
added based on msbuild parameters.
Another workaround which I used was using solution configuration in "Configuration Manager". I created two configurations for building each projects B or C which preprocessor directive is enabled in only one of these configurations.

I Know this topic is old - for me the following approach works nicely and might fit as well:
comments of (dis)advantages of this approach are welcome.
If you add your .cs-file as existing Item as a link to each project - you can compile it with different directives
For adding an existing item as a linked file see screenshots at this post
Use folders to organize linked files.
// file ClassA.cs
namespace HelperClasses
{
public ClassA
{
#if some_directive
// some code
#else
// some other code
#end
// ....
}
}
// using statement in Project B and C
using HelperClasses
// Add ClassA.cs in both Projects B and C
// as exiting, linked File -- not as a Reference
// set the compiler-Directives according your needs

Related

C# undefine project wide preprocessor

I have a C# project that has some solution wide defines in Conditional compilation symbols, see here
I now want to unit test that code and I need to undefine some of those variables.
For Unit testing I have a xUnit project that references the solution with the defines.
Is it possible in VS2019 to disable those defines?
Edit
In my specific case I have a Unity project added to my solution. Unity has Unity-specific code that cannot be executed in unit tests such like xUnit.
In order to cope with that, I wrap Unity-specific code (like Logging via Debug.Log) into a define UNITY_2020 that is automatically defined by the Unity project-file.
Now on the unit test side I want to undefine said preprocessor UNITY_2020. As I have the source code (no DLL or nuget), I hope that there is a way to compile and run my unit tests without having troubles with Unity-specific code.
So far, putting #undef UNTIY_2020 at the top of my test files does not help.
"Disable" is not quite the correct terminology, but that's ok. It is possible to undefine symbols by using the #undef preprocessor directive. You can read about it on C# preprocessor directives.
For example, you can place an #undef at the top of a file (actually anywhere really):
#undef CSHARP_7_OR_LATER
...
#if !CSHARP7_OR_LATER
// some code that can now be tested...
#endif
Also, preprocessor symbols apply to files (technically, to a compilation unit), and just happen to be commonly defined (or not) in your .csproj. At compile-time, these and passed to the compiler. So... they are not solution-wide unless you define them for all of the projects.
If the referenced projects are referenced via assembly or NuGet references, you will not be able to affect the compiled code, because, well, it's already compiled.
If, instead, you are referencing the projects directly, or the code directly (e.g. with add or add link) you can either modify the files as I stated, or you could create a new build configuration for each project and the solution, and then define (or not) the preprocessor symbols there.

How to avoid repeated constant string in .NET AssemblyVersion and AssemblyFileVersion

In a C# project, we increment versions manually and have a top-level file MyAssemblyInfo.cs containing
[assembly: AssemblyVersion("31.1.13")]
[assembly: AssemblyFileVersion("31.1.13")]
[assembly: AssemblyInformationalVersion("31.1.13-V1.0.0")]
I'd like to avoid repeating the version. For example, with the C preprocessor, one could write this as
#define VERSION "31.1.13"
[assembly: AssemblyVersion(VERSION)]
[assembly: AssemblyFileVersion(VERSION)]
[assembly: AssemblyInformationalVersion(VERSION "-V1.0.0")]
Is there a way to achieve this in C# without using any external tools?
[assembly: AssemblyFileVersion(AppVersion.Version)]
[assembly: AssemblyInformationalVersion(AppVersion.Version)]
// you can use + here but the format you use shows as invalid version for me
[assembly: AssemblyVersion(AppVersion.Version)]
// this must be at the end of the global declarations
internal class AppVersion
{
public const string Version = "31.1.13";
}
The short answer to your question is no you cannot use pre-processor directives in this manner. One work-around is stated in the other answer and involves defining a constant. This would be perhaps the only solution for old-style projects.
If you are using the SDK-style project format however, AssemblyInfo attributes can be set in the project file. The following properties correspond to the attributes defined above:
InformationalVersion -> AssemblyInformationalAttribute
AssemblyVersion -> AssemblyVersion
FileVersion -> AssemblyFileVersion
Version -> Can map to any/all of the above if they are omitted
Has special logic to remove suffix patterns when setting File/Assembly version
All other Assembly attributes can be set via properties so long as GenerateAssemblyInfo is true. This requires you to remove your AssemblyInfo.cs file to prevent duplication of those attributes.*
The way I have typically solved this is to define my own set of version-related properties in my project file (see notes below for why). For example, you might have the following:
<PropertyGroup>
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
<BaseVersion>31.1.13</BaseVersion>
<InfoSuffix>v1.0.0</InfoSuffix>
</PropertyGroup>
<PropertyGroup>
<!-- note: "-v1" is invalid in an Assembly Version; I assumed you meant this on the Informational one -->
<InformationalVersion>$(BaseVersion)-$(InfoSuffix)</InformationalVersion>
<AssemblyVersion>$(BaseVersion)</AssemblyVersion>
<FileVersion>$(BaseVersion)</FileVersion>
</PropertyGroup>
You could pass any of these properties on the command line to MSBuild or dotnet build if you wanted to explicitly override them:
dotnet build -p:InfoSuffix=v2.0+1234
# alternatively, specify the MSBuild properties directly
dotnet build -p:FileVersion=1.2.3.4 -p:InformationalVersion=5.6.7.8
If you have multiple projects you could set all of these properties inside of a Directory.Build.props file so that they apply to all of your projects at once.
Some Notes
First, if you are using the Directory.Build.props mechanism and running any sort of post-processing tasks or something like SourceLink (which appends info to the Informational version) you will need to move the second property group into a Directory.Build.targets file instead. You'd also need to do this if you wanted to pass the properties explicitly to other tooling, such as dotnet pack.
Second, MSBuild has a series of other version-related properties**. These include (but are not limited to):
SourceRevisionId - appended to the Informational version (our InfoSuffix)
VersionPrefix - A Base version
VersionSuffix - Sets prerelease label
PackageVersion - generates nuget version
You can use these in combination with those specified above instead. You can even pass them as properties on the command-line if you wanted to override the values in the project/props/targets files.
Now you might wonder why I bother defining my own properties instead of using the built-in ones. The reason is that MSBuild has some strange and sometimes unexpected behavior depending on how combinations of these properties are set. Anecdotally, I noticed different behavior depending on which values I was setting and whether I was building in VS, on the command line, or using dotnet pack. It is because of this I prefer defining my own properties and then using them to explicitly set the others. It also allowed me to use conditional MSBuild logic to set certain parts of the version easier. Though I do admit, your mileage may vary.
* If you want to keep the AssemblyInfo.cs file for other attributes, you'd have to disable their automatic generation by leveraging the individual GenerateX MSBuild properties.
** For a good explanation of some of these properties, see this blog post.

How to mark a part of c# code to be compiled if particular library is referenced and ignored if it isn't?

I would like to build a version of an application of mine without use of some features provided by a class library but avoid deleting the actual code (the code using the feature and the corresponding using directive).
Normally the whole application is going to fail to be built as soon as I unreference the assembly but I would like the dependent code parts to be excluded from compilation process instead.
Is this possible?
You can use preprocessor directives to control this - not on the basis of your references, but on the basis of symbols:
#if USE_SOME_LIBRARY
// Code that uses the library
#endif
Then just make sure that you define USE_SOME_LIBRARY in any build configurations where you have the reference.

C# how can I use #if to have different compile result for debug and release?

In C++ we can use #ifdef to eliminate some debug statements when we release. C# is different from C++ in preprocessor. Can I still get the same result useing C# #if. We want to eliminate ALL debug statements by change one place and we have several different types of debug statements. Can have one file which contains ALL our #ifdef flags to turn on or turn off those debug statements? thanks
You can wrap code in:
#if DEBUG
// debug only code
#endif
However, I don't recommend this. It's often a better alternative to just make a method and flag it with the [Conditional("DEBUG")] attribute. See Conditional on MSDN for more details. This allows you to make debug only methods:
[Conditional("DEBUG")]
public void DebugPrint(string output) { // ...
}
Then, you can call this normally:
DebugPrint("Some message"); // This will be completely eliminated in release mode
Use something like:
#if DEBUG
System.Console.WriteLine("This is debug line");
#endif
The according the MSDN docs
The scope of a symbol created by using #define is the file in which it was defined.
So you can't have a file that defines several other defines that are used throughout your program. The easiest way to do this would be to have different configurations on your project file and specifying the list of defines for each configuration on the command line to the compiler.
Update:
You can set your project defines in Visual Studio by right-clicking on your project and selecting Properties. Then select the Build tab. Under general you can specify the defines to be sent to the compiler under "Conditional compilation symbols". You can define different project settings using the Configuration Manager (Build->Configuration Manager)
Update 2:
When the "Conditional compilation symbols" are specified, Visual Studio emits a /define on the command line for the compiler (csc.exe for C#), you can see this by examining the output window when building your project. From the MSDN docs for csc.exe
The /define option has the same effect
as using a #define preprocessor
directive except that the compiler
option is in effect for all files in
the project. A symbol remains defined
in a source file until an #undef
directive in the source file removes
the definition. When you use the
/define option, an #undef directive in
one file has no effect on other source
code files in the project.
You can use symbols created by this
option with #if, #else, #elif, and
#endif to compile source files conditionally.

Using C# preprocessor to add reference

I have a large application that I can build through the command line. I want to specify a flag that enables me to compile it into either one of two modes, Actual or Simulated.
So the main issue is, how can I use the preprocessor to programmatically add a reference?
For example:
#if SIMULATED
include SimulatedFiles;
myFactory = new SimulatedFiles.simFactory();
#else
myFactory = new realFactory();
#endif
I don't want any simulated files to compiled into my "actual" application. Since there is no "include" directive in C#, I am stuck on how to accomplish this.
You cannot do this via a C# preprocessor statement because the language doesn't support the notion of references via preprocessor macros.
What you can do is use a msbuild file and alter the set of references added based on msbuild parameters.
nant/msbuild and dependency injection tool with xml configuration?
In C#, there is no real preprocessor, as you can read on the C# Preprocessor's documentation.
From the documentation (emphasis mine):
While the compiler does not have a separate preprocessor, the directives described in this section are processed as if there was one; these directives are used to aid in conditional compilation. Unlike C and C++ directives, you cannot use these directives to create macros.
Are the include files your own source code, or third-party assembly dlls?
If they are your own sources, then you can easily use conditional compilation to remove the "simulated" code from your release build, exactly as you have done in your example (just replace 'include' with 'using'). This is common practice with debugging classes for example.
If you don't "control" the source code for the includes, then you can still add a project reference, but if you conditionally compile all the code that uses the assembly, your applicaton won't ever attempt to access the assembly, so it doesn't need to be be present when the code is running.
(Another possiblity that seems less useful for you is to write a "dummy" version of the referenced assembly that you ship in place of the "real" one, or a proxy that calls the real third-party dll in simulated builds only. If it supplies the public classes and methods that you call, you can ship the dummy instead of the simulated assembly to your customers)

Categories

Resources