Use types from .NET 5.0 while remaining compatible with earlier .NET versions like .NET Core 3.1

202 Views Asked by At

Suppose you would want to utilize the new System.Half, but you also want your library to be used by .NET Core 3.1 apps (or older). I could simply copy the System.Half implementation and lose the intrinsic optimized behavior for older .NET versions, but can I do so in a single assembly?

As far as I know this isn't possible (barring a reflection-style approach, or emit-IL-on-first-use craziness): the above scenario would require separate builds for .NET 5.0 using the build-in System.Half) and older .NET versions (using our internal System.Half).

But I'm hoping if there's some way to compile/configure a single assembly with some creative type forwarding to utilize the .NET 5.0 version of a given type when it is available, or a shim otherwise.

(this question is language-agnostic, and not specific to just System.Half)

2

There are 2 best solutions below

1
On BEST ANSWER

In a nutshell: No, it is not possible in a single assembly - this would need to be done by multi-targeting your library 5.0+ and the lowest version of .NET CCore you want to support and creating a NuGet package of this library.

Applications using the library would then select the best matching assembly, so .NET 5/6/+ Apps would get your .NET 5.0 slice using the runtime's System.Half implementation and .NET Core 3.1 Apps would get the other slice containing your implementation of System.Half that you put behind an #if.

Even if you don't want to multi-target your library, a different NuGet package would be needed that provides a slice for .NET (Core) < 5.0 containing an implementation of System.Half. Your library would then depend on this package causing consumers to transitively use this package.

11
On

Usually, it comes down to: is there a nuget package available that offers some part of the API? Note that in the case of something primitive like Half, even if there is a nuget package, it might be implemented differently - i.e. no inbuilt JIT/intrinsic support - but it might still work. As an example, consider Span<T>, which works in down-level frameworks (via nuget), but which works best in .NET Core 3.1 or above. As another example, consider IAsyncDisposable/IAsyncEnumerable<T>, which are available via a nuget package.