Shared Projects and C#: Best Practices
This blog post is going to go in-depth into when and how you should make use of "shared projects" in Visual Studio, when developing C# class libraries and targeting multiple .NET Framework profiles and versions.
Visual Studio 2015 introduced the concept of Shared Projects, that was intended to be introduced as a portable solution for code-sharing between projects, and as an alternative to portable class libraries (PCLs). Shared Projects function as Visual Studio or MSBuild projects that are not meant to be compiled, but are instead meant to be referenced by other application and class library projects.
Code files that are referenced by Shared Projects, are subsequently ingested by the projects that reference a Shared Project. In effect, this means that code files are included as part of a Shared Project, will compile alongside code that is featured in a Class Library or Desktop Application project.
Shared Project Structure
Shared Projects come with two separate project files that represent their appearance in Visual Studio and appearance overall.
- The "root" or "parent" project that imports or consumes the .projitems project.
- Defines all the files that are referenced and consumed by the shared project.
.NET Framework version releases are frequent, and quite often major version releases will introduce valuable features that should be integrated as part of your class library or application.
The problem is that as your shared code solution grows, and as you have an increasing amount of projects that target older versions of .NET Framework, you will begin to encounter compilation issues or warnings.
Portable Class Libraries were heavily relied upon in the past as a suitable way of shared code that was to be consumed across platforms (operating systems). It would often be the case that shareable types would be defined in a single Portable Class Library project, that would then be referenced by a platform-specific version of that Portable Class Library project (i.e. Mono on Mac and Linux, or .NET Framework on Windows), which would then provide and inject platform-specific implementations of those shareable types.
Refer to this MSDN page about Portable Class Libraries and cross-platform development.
Because Shared Projects in Visual Studio are still fundamentally MSBuild Projects, it still means that you can write MSBuild targets that can be shared between projects that reference your Shared Project.
Let's assume for a second that you have a class library that contains plenty of useful and shareable code. You are intending on referencing this code in multiple projects that vary in .NET Framework versions. The most optimal method of addressing this problem is by making use of one Shared Project for your class library, and having multiple (basically empty) Class Library projects reference the same Shared Project.
These empty Class Library projects can then target the version of .NET Framework than they need to, while also referencing the code that they must be compiled with.
- Reduces code duplication and the need for project hackery for including code files as "external items".
- Increases portability.
- Removes dependency of portable class libraries (PCLs)
- Removes the requirement for there to be another assembly available that is referenced or consumed by the platform or framework specific assembly.