Conditionally compiling entire namespaces - C# - c#

I was wondering if there is a way to conditionally compile entire namespaces in C#. Or am I left with having to explicitly decorate each source file within the namespace with the preprocessor directives to exclude it? In sub-versions of my application the code in various namespace is simply not required and I would like it excluded.
Thanks in advance!

If your namespace is in a separate assembly which doesn't contain anything else you can use the Configuration Manager for your specific sub-version and untick the "Build" check box.
If you've got other classes in the assembly though they will not be built or included obviously, and then the only way would be to decorate with pre-processor declarations.

You would need to put the conditional compilation directive in each file. There is no way to mark an entire namespace as conditionally compiled.
As Michael notes in his answer, a possible solution is to break out the conditional code into a separate project (assembly), and ship that assembly only for configurations that require it; but this will depend on the nature of the conditional code.

You can do this by decorating each file, or you could do it by choosing which files to include. Both MSBuild and csc have options for including all files under a path, and MSBuild additionally has the ability to conditionally include build items based on an attribute (rather than requiring a separate csproj per configuration).
But it is probably easier to decorate the files directly ;-p

I had the same problem, and using directives in each file eventually became too much work; so I started using conditional <ItemGroup> tags in the .csproj file.
For example, if I need to exclude some files from a build, I will move these files into a new <ItemGroup> section...
<ItemGroup Condition=" '$(SlimBuild)' != 'true' ">
...
</ItemGroup>
...and call msbuild.exe with a matching property parameter.
MSBuild.exe MyApp.msbuild /p:Configuration=Release /p:SlimBuild=true
You could probably also use wildcards to include future files.
<ItemGroup>
<Compile Include=".\SomePath\*.cs" />
</ItemGroup>

Related

VS2017 Directory.Build.props doesn't load for whole solution

OK here is my problem I have 2 library and 2 project that include their .csproj (1 for Dev, 1 for Client Delivery).
I need a Defined constant to set accessible most of my class when we are with the Dev purpose (internal -> public).
I used a Directory.Build.props in my dev project directory that defined a variable and my Libraries .csproj define a constant if this variable exists.
<PropertyGroup Condition ="$(ActiveIHMMode)=='true'">
<DefineConstants>$(DefineConstants);DEV_IHM_MODE</DefineConstants>
</PropertyGroup>
I can see everything work well for my dev proj but it doesn't for my Libraries (they don't see my .props variable)
I assume there is a simple reason for it, it's because of dependencies compile order.
My directory Hierarchie is the following :
LibA
LibB
ProjectDelivery
ProjectDev
My LibA is compiled first and doesn't find any Directory.Build.props because my file is in my ProjectDev Directory, but my ProjectDev as the last element to compile finds it, but it's too late for my Lib.
First time using .props and I can't see a way to resolve it. Thanks for your future help.
First of all, to clarify a possible confusion inferred from your title, automatically importing Directory.Build.props is not a Visual Studio 2017 feature, but a MSBuild 15 feature (which is included with VS2019).
With my nitpicking out of the way, let's get technical:
The problem is not your build order. The reason Directory.Build.props is only picked up in your ProjectDev project, is because MSBuild looks in the directory of the .csproj for a file called Directory.Build.props and imports it if it finds it. If it is not found, the file is searched in the parent directory. And it keeps looking for the Directory.Build.props in the parent directory until it reaches the root, or it actually finds that file and then stops, so it only automatically imports the first Directory.Build.props found.
Your project structure, as described above, looks like this:
/LibA/
/LibA/LibA.csproj
/LibB/
/LibB/LibB.csproj
/ProjectDelivery/
/ProjectDelivery/ProjectDelivery.csproj
/ProjectDev/
/ProjectDev/ProjectDev.csproj
/ProjectDev/Directory.Build.props
Only ProjectDev gets the Directory.Build.props automatically imported; none of the other projects have a Directory.Build.props neither in their directory nor in any of their parent directories.
To fix your issue you can either move the Directory.Build.props one folder up, so that it gets automatically imported by all of your projects,
or you may import the Directory.Build.props manually by adding an Import element to your .csproj:
<Project>
<Import Project="..\ProjectDev\Directory.Build.props" />
</Project>
You can read up on more details about Directory.Build.props in the documentation.

exclude certain projects from using Directory.Build.props

i have a new visual studio solution that has around 350 projects. it takes visual studio a lot of time to compile the .sln file so i implemented Directory.Build.props to avoid copying of references that are not needed to copy to the local directory so the build can be made quicker. below is the code that im using inside the Directory.Build.props file under the root folder.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemDefinitionGroup>
<Reference>
<Private>False</Private>
</Reference>
<ProjectReference>
<Private>False</Private>
</ProjectReference>
</ItemDefinitionGroup>
</Project>
since i placed Directory.Build.props under root folder it is being applied for all projects.
Question::
how can i exclude few projects from applying Directory.Build.props so that the references can be copied to the local.
in short i want the Directory.Build.props to be applied to only 300 projects under the solution file remaining 50 projects need to be excluded from this
how/where can i write a condition in the above code that will exclude certain projects being affected by this code
For others dealing with the same problem, there is another trick that can be used to exclude certain project from using the Directory.Build.props file found at root level.
If you add a dummy Directory.Build.props file in the project you want to exclude, then the Directory.Build.props from the root will not be used. This is because MSBuild walks the directory structure upwards from the location of your project, until it locates the first Directory.Build.props. That will be used. This behavior is documented on the Customize your build page under Search scope at the Microsoft docs.
Sample of the dummy Directory.Build.props:
<Project>
<!-- Only here so that the default Directory.Build.props will not be used. -->
</Project>
I found this to be a convenient way to solve this issue. Especially when dealing with only a few projects that need to be excluded.
I had to work around this in a bit of a hacky way.
In my example, there was a custom analyzer project I wrote that I did not want included in another set of projects. I ended up writing something like this in my Directory.Build.props:
<Project>
...
<Choose>
<When Condition="$(MSBuildProjectName)!='Analyzer' AND ...">
<ItemGroup>
<ProjectReference Include="..\Analyzer\Analyzer.csproj">
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
<OutputItemType>Analyzer</OutputItemType>
</ProjectReference>
</ItemGroup>
</When>
<Otherwise>
...
</Otherwise>
</Choose>
...
</Project>
Where I filled in ... with the projects I wanted it to skip.
I understand this may not be the exact answer you were looking for, but I did a ton of research and was also unable to find any way to do it the way you described. The stuff I have posted was the only way I was able to achieve the ability to exclude certain things from being applied to specific projects by filtering via name. I know that this is hacky and sucks, but it's the only thing that was able to work for me.
Also note that <Otherwise></Otherwise> may be turned into <Otherwise /> possibly, and may even be optional altogether. I left it there so that you could place stuff inside of it if needed.

Is there a way to override attributes from AssemblyInfo.cs (e.g. AssemblyVersionAttribute)?

I'm using dotnet core. This is for a CI process, not local builds. I'd like to allow devs to create AssemblyInfo.cs files for things like title etc but I'd like my build process to have control over the assembly's version.
Currently I'm using the "dotnet build ... /p:Version=1.2.3.4" command, but as soon as an AssemblyInfo.cs file is present this version number is superseded, even if the AssemblyInfo.cs doesn't specify any version properties.
The only way I can control the version from the CLI is to remove the AssemblyInfo.cs file. Is there any way of doing this without resorting to manually altering the AssemblyInfo.cs file before build?
The tooling generates a custom .cs file containing assembly attributes. The compiler only allows each attribute to be defined just one. Usually you'd turn off the automatic assembly info generation completely, but the SDK enables you to control the generation of each attribute individually.
So if you edit the csproj file to contain these property group (inside the <Project> element):
<PropertyGroup>
<!-- true is the default here -->
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
<GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>
<GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute>
</PropertyGroup>
These properties won't be auto-generated during compilation and you can define them in a custom property. The complete list is available in the dotnet/sdk repo.

C# using statement inside #if DEBUG but not ship assembly

I have a feature that I only want to happen on Debug, but do not want to ship the dll's that this feature requires. Is that possible to do?
I have:
#if DEBUG
using MyAssembly;
#endif
Of course MyAssembly is being referenced by the project. I would like MyAssembly.dll to not be shipped on a release mode. Can that be achieved? Will using Conditional("DEBUG") help in this regard?
References that aren't required are usually removed automatically by the compiler, however: you can be more explicit by changing the csproj to include a Condition on the PropertyGroup. Something like:
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<Reference Include="YourReference" />
</PropertyGroup>
(it could also be a <PackageReference> etc)
It's perfectly fine to put a using directive in an #if DEBUG section, and it will remove that directive when compiled for debug.
However, that's only part of the story; it won't accomplish your objective by itself. The Solution Explorer in Visual Studio also has a References section. You would need to remove the reference for the assembly, as well, or it will still be included when you build.
I don't recall anything in the Visual Studio user interface that will let you do this, but I expect it should be possible somehow if you manually edit the Project file (it's just an MSBuild file). Personally, I try very hard to avoid doing things that require manual edits to the project files. Visual Studio wants to be able to own these files, and you can end up creating conflicts, where you and Visual Studio overwrite each other's changes.

Using the same assembly references in csproj with different folder structures

I have a C# project, MyProject.csproj that sits in a solution with the following folder structure and references Dependency.dll:
Libs
Dependency.dll
Projects
MyProject
MyProject.csproj
Thus the reference to Dependency.dll in MyProject.csproj has a HintPath of something like this:
..\..\Libs\Dependency.dll
Now I'd like to use MyProject in a different solution in a different project structure, without modifications, as source. This is because MyProject sits in its own source control repository and I'm using it in different solutions as Mercurial subrepositories/Git submodules. (The problem might be solved on the source control level...) Such a diffreent solution would look like this:
Libs
Dependency.dll
MyProject
MyProject.csproj
Note that the MyProject folder is now on the same level as the Libs folder. Thus the original HintPath is now invalid (since it should be ..\Libs\Dependency.dll) and I get build errors.
Is there a way to fix this but keep the same csproj across the different solutions?
I found the following possible solutions which are great but require the modification of the csproj. This is mostly possible in my case but sometimes there are external components where I can't request such modifications, so I'd look for some solution-level override if possible.
Conditional HintPath based on file existence check: .csproj multiple hint paths for an assembly This might work as for the majority of cases the solution structure is well-known here.
Specifying multiple assembly search locations: https://stackoverflow.com/a/15816779/220230
Thank you.
For now, I solved the issue using the technique outlined in this blog post.
<ItemGroup>
<LibReferenceSearchPathFiles Include="..\..\Libs\**\*.dll">
<InProject>false</InProject>
</LibReferenceSearchPathFiles>
</ItemGroup>
<Target Name="BeforeResolveReferences">
<RemoveDuplicates Inputs="#(LibReferenceSearchPathFiles->'%(RootDir)%(Directory)')">
<Output TaskParameter="Filtered" ItemName="LibReferenceSearchPath" />
</RemoveDuplicates>
<CreateProperty Value="#(LibReferenceSearchPath);$(AssemblySearchPaths)">
<Output TaskParameter="Value" PropertyName="AssemblySearchPaths" />
</CreateProperty>
</Target>
This enables dlls from subfolders of Libs to be loaded. If all the dlls would be in the root of the Libs folder, then the first wildcard can be removed from the Include value.

Categories