Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

.NET Standard, What are the Alternatives?

4.62/5 (4 votes)
19 May 2020CPOL4 min read 7.5K  
An explanation of how to support multiple platforms in .NET development
An explanation is given of .NET Standard, when alternatives are useful and what alternatives are possible. Two examples of such alternatives are given.

Introduction

Many developers are familiar with .NET Standard . As the name suggests, it is a standard for .NET since .NET Framework is not the only supported platform. Creating a .NET Standard project, enables us to write and compile code to be used for multiple platforms. Which platforms are supported depends a bit on which .NET Standard version you choose but the general list is long: .NET Core, .NET Framework, Mono, Xamarin.iOS, Xamarin.Mac, Xamarin.Android, Universal Windows Platform and Unity.

That is good if your code is really generic, for example if you create a client package or implement a math model. However, once some code or NuGet Package has a dependency on some specific platform, .NET Standard is not going to be helpfull. .NET Standard is standard, not platform specific. So how to target multiple platforms in such a situation?

Background

It will be really helpfull if you have experience with .NET development and preferably with multiple platforms or multiple versions of a platform.

Using the code

The first step is really simple: target the TargetFrameworks instead of the TargetFramework in our project file. Since that is what we want to do anyway.

C#
<PropertyGroup>
  <TargetFrameworks>netcoreapp3.1;netcoreapp2.1</TargetFrameworks>
</PropertyGroup>

Now, we start coding a dummy class and see if it works.

C#
public class DummyClass : IAsyncDisposable
{
    public void DoSomething()
    {
        Console.WriteLine("Something needs is done");
    }

    public void Dispose()
    {
        Console.WriteLine("Object is disposed");
    }

    public async ValueTask DisposeAsync()
    {
        Console.WriteLine("Object is disposed asynchronously");
    }
}

We get a compiler error here:

Quote:

error CS0246: The type or namespace name 'IAsyncDisposable' could not be found (are you missing a using directive or an assembly reference?)

The error is right. We are trying to target a recent .NET Feature in a non recent .NET Core version.  But for .NET Core 3.1, such an error should not occur. We need to explain in our code which part is platform specific:

C#
public class DummyClass
    #if NETCOREAPP3_1
    : IAsyncDisposable
    #endif
{
    public void DoSomething()
    {
        Console.WriteLine("Something needs is done");
    }

    public void Dispose()
    {
        Console.WriteLine("Object is disposed");
    }

    #if NETCOREAPP3_1
    public async ValueTask DisposeAsync()
    {
        Console.WriteLine("Object is disposed asynchronously");
    }
    #endif
}

By using the #if directive, it becomes clear that some code is .NET Core 3.1 specific. The other code can be compiled for both platforms.

Adding NuGet packages that are platform specific is also possible. This is how it works:

C#
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp3.1'">
  <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="3.1.4" />
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.1'">
  <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="2.1.3" />
</ItemGroup>

Adding a Condition ensures the right depency is resolved for the right platform. This approach works but has its issues:

  • You need to manually change your csproj file.
  • The more platforms you add, the more complex your csproj file becomes.
  • The more platforms you add, the more complex your code becomes.

From a maintainability point of view, this may not be the situation you want. That is why an alternative for this approach needs to be explained: Shared projects with partial classes. The first step is to create a shared project, which is just a project type available in Visual Studio. In the shared project, we add a partial class that just includes code that is expected to compile for each platform we want to target. Here it is:

C#
public partial class DummyClass : IDisposable
{
    public void DoSomething()
    {
        Console.WriteLine("Something needs is done");
    }

    public void Dispose()
    {
        Console.WriteLine("Something is disposed");
    }
}

Shared projects cannot be compiled but the code inside a shared project can be compiled. Therefore, we need to reference it in our .NET Core 2.1 project. If you have never worked with shared projects before, this is how you add such a reference. The .NET Core 2.1 project compiles since the IAsyncDisposable interface is not there . But for the .NET Core 3.1 project, we need it. Therefore, we add a partial class there too.

C#
public partial class DummyClass : IAsyncDisposable
{
    public async ValueTask DisposeAsync()
    {
        Console.WriteLine("Object is disposed asynchronously");
    }
}

It seems that we just resolved the mentioned issues:

  • No manual changes to the project file required.
  • More platforms only means more projects. The project files are all simple.
  • The code files are short and simple

However, this approach has an issue too: there are more projects to maintain. Moreover, you cannot generate a NuGet package from a shared project.  If you are interested in working examples for both solutions, download the code from GitHub.

Points of Interest

Shared projects are especially popular in the world of Xamarin development but can be used for other purposes too. In many companies, junior developers are told that duplicating code is a bad thing because it makes maintaining your code harder. However, what we often forget to tell them is that Shared projects has the same effect (the same code is compiled in different projects) but without its disadvantages (the code needs to be maintained in just one file being part of one project). I became a big fan of Shared Projects. However, each solution has disadvantages as I mentioned.

History

  • 16th May, 2020: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)