Open3

【C#】古い環境向けでもなるべく最新で書く

いぬいぬいぬいぬ

ライブラリはnugetで探す

新しく追加された公式APIは、ライブラリとしても公開されている事が多い。

たとえばTimeProviderは.NET8以降だが、
nugetで追加ライブラリとしても公開されていて、
対応バージョンが「.NET Standard 2.0」や「.NET Framework 4.6.2」の古い環境でも使える。

https://www.nuget.org/packages/Microsoft.Bcl.TimeProvider

  • .NET 8
  • .NET Standard 2.0
  • .NET Framework 4.6.2

APIリファレンス(MS learn)にはこのことが書かれてないので注意。
対応バージョンだけで判断してはいけない。

https://learn.microsoft.com/ja-jp/dotnet/api/system.timeprovider?view=net-8.0

MSが公式に出している事が多いのでMicrosoft.~で始まる名前で調べると出たりする

  • Microsoft.Bcl.~
いぬいぬいぬいぬ

.NET Standard2.0でも使える新しめのAPI

追加ver: .NET 8 ~

FrozenDictionary<T> / FrozenSet<T>

https://www.nuget.org/packages/System.Collections.Immutable/

https://learn.microsoft.com/ja-jp/dotnet/core/whats-new/dotnet-8#performance-focused-types

TimeProvider

Microsoft.Bcl.TimeProvider

https://www.nuget.org/packages/Microsoft.Bcl.TimeProvider

https://www.roundthecode.com/dotnet-tutorials/timeprovider-easier-mock-time-dotnet-8
https://aneuf.hatenablog.com/entry/2023/11/27/210000

XxHash3 / XxHash128

System.IO.Hashing

https://www.nuget.org/packages/System.IO.Hashing/

追加ver: .NET Core 2.1 / .NET Standard 2.1~

Span<T> / Memory<T>

System.Memory

System.Span
System.ReadOnlySpan
System.Memory
System.ReadOnlyMemory
System.Buffers.MemoryPool
System.Buffers.ReadOnlySequence
System.Buffers.Text.Utf8Parser
System.Buffers.Text.Utf8Formatter

https://www.nuget.org/packages/System.Memory/

https://zenn.dev/link/comments/42348679d9c6e6

ArrayPool<T>

System.Buffers

https://learn.microsoft.com/ja-jp/dotnet/api/system.buffers.arraypool-1?view=net-8.0

https://www.nuget.org/packages/System.Buffers

(C#) ArrayPool<T>.Shared 解体新書 - ネコのために鐘は鳴る

System.IO.Pipelines

System.IO.Pipelines.Pipe
System.IO.Pipelines.PipeWriter
System.IO.Pipelines.PipeReader

https://devblogs.microsoft.com/dotnet/system-io-pipelines-high-performance-io-in-net/

https://www.nuget.org/packages/System.IO.Pipelines/

IAsyncEnumerable<T> / IAsyncEnumerator<T> / IAsyncDisposable<T>

await usingが使えるようになる

Microsoft.Bcl.AsyncInterfaces

IAsyncEnumerable<T>
IAsyncEnumerator<T>
IAsyncDisposable<T>

https://www.nuget.org/packages/microsoft.bcl.asyncinterfaces/

いぬいぬいぬいぬ

最新のSDKで古い環境向けに出力設定する

TargetFramework(s)

csprojのTargetFrameworkで古いverを指定すれば出力できる。
最新.NET SDKで.NET Framework ランタイム向けに書き出せる。

大抵は、.NET Starndard 2.0を指定しておけば大体は大丈夫。

csproj
<TargetFramework>netstandard2.0</TargetFramework>

ライブラリとかで古い環境向けと最新向けどちらも出しておくのはTargetFrameworksを指定する。

.NET Stardard2.0(古い環境向け)と.NET8向けに設定する方法
<TargetFrameworks>netstandard2.0;net8</TargetFrameworks>

こうしておくと互換性をもったまま、新しい環境だと最適化とかが効いて高速・省メモリにできたりする。

LangVersion

LangVersionlatestにすれば使っているSDKが対応する最新のC#の言語バージョンが使える。

<LangVersion>latest</LangVersion>

使えると言っても公式そのままでは公式APIが無いとかで実際にはコンパイルエラー・ランタイムエラーになるので注意。

  • 公式APIは別ライブラリとしてnuget公開されてる場合は導入する
  • polyfillを使うことで解決するものもある
  • ランタイム対応が必要なものは辛い

.NET9.0以降は、latestは非推奨になるらしい
https://ufcpp.net/blog/2024/2/breaking-changes/

ポリフィル(polyfill)

C#界隈だとあまり活用されてないけど、JS/Pythonとかだとよくあるメジャーな手法。
(特にエンジンがバラバラに実装されるJS)

コンパイルエラーに関してはpolyfillのライブラリを導入することで使えるようになるものがある。

https://note.dokeep.jp/post/csharp-polyfill/

有名なのは「PolySharp

https://github.com/Sergio0694/PolySharp

対応リストはこの辺
https://github.com/wallyrion/PolySharp.Playground
https://gitlab.com/-/snippets/2367119
https://sergeyteplyakov.github.io/Blog/c%23/2024/03/06/CSharp_Language_Features_vs_Target_Frameworks.html

PolySharpだけで上手くいかないのはnugetで追加導入;

  • Index / Range
    • ※publicなメンバーの型などで使うときに必要
    • IndexRange