{"id":16554570,"url":"https://github.com/tyrrrz/polyshim","last_synced_at":"2026-04-05T15:01:27.616Z","repository":{"id":151008114,"uuid":"623372318","full_name":"Tyrrrz/PolyShim","owner":"Tyrrrz","description":"Collection of polyfills for projects targeting older versions of .NET","archived":false,"fork":false,"pushed_at":"2026-03-31T16:12:31.000Z","size":506,"stargazers_count":71,"open_issues_count":1,"forks_count":5,"subscribers_count":2,"default_branch":"prime","last_synced_at":"2026-03-31T18:18:38.004Z","etag":null,"topics":["backwards-compatibility","compat","compatibility","dotnet","dotnet-core","dotnet-framework","dotnet-standard","polyfill","shim"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Tyrrrz.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":"License.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"Tyrrrz","patreon":"Tyrrrz","custom":["tyrrrz.me/donate"]}},"created_at":"2023-04-04T08:38:15.000Z","updated_at":"2026-03-23T22:08:38.000Z","dependencies_parsed_at":"2024-04-28T17:23:19.660Z","dependency_job_id":"506026cc-a91d-4629-8cb7-ed7b79e8c1ea","html_url":"https://github.com/Tyrrrz/PolyShim","commit_stats":null,"previous_names":[],"tags_count":26,"template":false,"template_full_name":null,"purl":"pkg:github/Tyrrrz/PolyShim","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tyrrrz%2FPolyShim","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tyrrrz%2FPolyShim/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tyrrrz%2FPolyShim/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tyrrrz%2FPolyShim/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Tyrrrz","download_url":"https://codeload.github.com/Tyrrrz/PolyShim/tar.gz/refs/heads/prime","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tyrrrz%2FPolyShim/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31439442,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-05T13:13:19.330Z","status":"ssl_error","status_checked_at":"2026-04-05T13:13:17.778Z","response_time":75,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["backwards-compatibility","compat","compatibility","dotnet","dotnet-core","dotnet-framework","dotnet-standard","polyfill","shim"],"created_at":"2024-10-11T19:51:49.026Z","updated_at":"2026-04-05T15:01:27.602Z","avatar_url":"https://github.com/Tyrrrz.png","language":"C#","funding_links":["https://github.com/sponsors/Tyrrrz","https://patreon.com/Tyrrrz","tyrrrz.me/donate"],"categories":[],"sub_categories":[],"readme":"# PolyShim\n\n[![Status](https://img.shields.io/badge/status-active-47c219.svg)](https://github.com/Tyrrrz/.github/blob/prime/docs/project-status.md)\n[![Made in Ukraine](https://img.shields.io/badge/made_in-ukraine-ffd700.svg?labelColor=0057b7)](https://tyrrrz.me/ukraine)\n[![Build](https://img.shields.io/github/actions/workflow/status/Tyrrrz/PolyShim/main.yml?branch=prime)](https://github.com/Tyrrrz/PolyShim/actions)\n[![Coverage](https://img.shields.io/codecov/c/github/Tyrrrz/PolyShim/prime)](https://codecov.io/gh/Tyrrrz/PolyShim)\n[![Version](https://img.shields.io/nuget/v/PolyShim.svg)](https://nuget.org/packages/PolyShim)\n[![Downloads](https://img.shields.io/nuget/dt/PolyShim.svg)](https://nuget.org/packages/PolyShim)\n[![Discord](https://img.shields.io/discord/869237470565392384?label=discord)](https://discord.gg/2SUWKFnHSm)\n[![Fuck Russia](https://img.shields.io/badge/fuck-russia-e4181c.svg?labelColor=000000)](https://twitter.com/tyrrrz/status/1495972128977571848)\n\n\u003ctable\u003e\n    \u003ctr\u003e\n        \u003ctd width=\"99999\" align=\"center\"\u003eDevelopment of this project is entirely funded by the community. \u003cb\u003e\u003ca href=\"https://tyrrrz.me/donate\"\u003eConsider donating to support!\u003c/a\u003e\u003c/b\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n\u003c/table\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"favicon.png\" alt=\"Icon\" /\u003e\n\u003c/p\u003e\n\n**PolyShim** is a collection of polyfills that enable many modern framework APIs and compiler features for projects targeting older versions of .NET.\nIt's distributed as a source-only package that can be referenced without imposing any run-time dependencies.\n\n## Terms of use\u003csup\u003e[[?]](https://github.com/Tyrrrz/.github/blob/prime/docs/why-so-political.md)\u003c/sup\u003e\n\nBy using this project or its source code, for any purpose and in any shape or form, you grant your **implicit agreement** to all the following statements:\n\n- You **condemn Russia and its military aggression against Ukraine**\n- You **recognize that Russia is an occupant that unlawfully invaded a sovereign state**\n- You **support Ukraine's territorial integrity, including its claims over temporarily occupied territories of Crimea and Donbas**\n- You **reject false narratives perpetuated by Russian state propaganda**\n\nTo learn more about the war and how you can help, [click here](https://tyrrrz.me/ukraine). Glory to Ukraine! 🇺🇦\n\n## Install\n\n- 📦 [NuGet](https://nuget.org/packages/PolyShim): `dotnet add package PolyShim`\n\n\u003e [!IMPORTANT]\n\u003e To reference this package, you must have the latest major version of the .NET SDK installed.\n\u003e This is only required for the build process, and does not affect which version of the runtime you can target.\n\n\u003e [!NOTE]\n\u003e Installing this package automatically sets your project's target language version to latest.\n\u003e This is required for many polyfills to work, but is also recommended, since **PolyShim** provides the facilities to use modern language features on older frameworks.\n\u003e If you have `\u003cLangVersion\u003e` explicitly configured in your project file, make sure it's set to `latest` or newer (e.g. `preview`).\n\n## Features\n\n- Enables compiler support for:\n  - [Nullable reference types](https://learn.microsoft.com/dotnet/csharp/language-reference/builtin-types/nullable-reference-types)\n  - [Record types](https://learn.microsoft.com/dotnet/csharp/language-reference/builtin-types/record)\n  - [Init-only properties](https://learn.microsoft.com/dotnet/csharp/language-reference/keywords/init)\n  - [Required properties](https://learn.microsoft.com/dotnet/csharp/language-reference/keywords/required)\n  - [Value tuples](https://learn.microsoft.com/dotnet/csharp/language-reference/builtin-types/value-tuples)\n  - [Index and range operators](https://learn.microsoft.com/dotnet/csharp/language-reference/language-specification/ranges)\n  - [Caller information](https://learn.microsoft.com/dotnet/csharp/language-reference/attributes/caller-information)\n  - Module initializers\n  - Overload priority\n- Provides type polyfills for:\n  - `ValueTuple\u003c...\u003e`\n  - `Index` and `Range`\n  - `Span\u003cT\u003e` and `Memory\u003cT\u003e`\n  - `Lock`\n  - `HashCode`\n  - `ArrayPool\u003cT\u003e`\n  - `TaskCompletionSource`\n  - [...and 70+ more](Signatures.md)\n- Provides member polyfills for:\n  - `string.ReplaceLineEndings(...)`, `string.AsSpan()`, etc.\n  - `Stream.ReadExactly(...)`, `Stream.ReadAtLeast(...)`, etc.\n  - `IEnumerable\u003cT\u003e.Chunk(...)`, `IEnumerable\u003cT\u003e.TakeLast(...)`, etc.\n  - `Task.WaitAsync(...)`, `Task.WhenEach(...)`, etc.\n  - `Parallel.ForEachAsync(...)`, `Parallel.ForAsync(...)`, etc.\n  - `File.WriteAllTextAsync(...)`, `File.ReadAllTextAsync(...)`, etc.\n  - `Environment.ProcessPath`, `Environment.ProcessId`, etc.\n  - `OperatingSystem.IsWindows()`, `OperatingSystem.IsLinux()`, etc.\n  - [...and 250+ more](Signatures.md)\n- Adjusts polyfills based on available capabilities\n- Targets .NET Standard 1.0+, .NET Core 1.0+, .NET Framework 3.5+\n- Imposes no run-time dependencies\n\n## Usage\n\n**PolyShim** polyfills come in two forms:\n\n- **Type polyfills**, which define missing built-in types by reimplementing them from scratch.\n- **Member polyfills**, which are provided through global extension members that substitute missing members on existing built-in types.\n\nOnce the package is installed, the polyfills will be automatically added to your project as internal source files.\nYou can then use them in your code by referencing the corresponding types or members as if they were defined natively.\n\n\u003e [!NOTE]\n\u003e Polyfills are only applied to types and members that are not already provided.\n\u003e When a native implementation of a symbol is available — either in the framework or through a referenced [compatibility package](#compatibility-packages) — it will always be prioritized over the corresponding polyfill.\n\n### Type polyfills\n\n**PolyShim** provides various types that are not available natively on older target frameworks.\nThese types are defined within the corresponding `System.*` namespaces and mimic the behavior of their original implementations as closely as possible.\n\nFor example, with **PolyShim** you can use the `Index` and `Range` structs (added in .NET Core 3.0) on any version of .NET:\n\n```csharp\nusing System;\n\n// On newer frameworks, this references the framework-provided types.\n// On older frameworks, this references the polyfilled types.\n// Same code works everywhere without any changes.\nvar index = new Index(1, fromEnd: true);\nvar range = new Range(\n    new Index(3),\n    new Index(1, true)\n);\n```\n\nYou can also use compiler features that rely on these types, such as the advanced indexing and slicing operators:\n\n```csharp\nvar array = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };\n\n// On newer frameworks, these operators rely on the framework-provided types.\n// On older frameworks, these operators rely on the polyfilled types.\n// Same code works everywhere without any changes.\nvar last = array[^1];\nvar part = array[3..^1];\n```\n\n\u003e [!NOTE]\n\u003e You can find the full list of type polyfills [here](Signatures.md).\n\n### Member polyfills\n\n**PolyShim** provides a number of extension members that act as shims for instance or static members that are not available natively on older target frameworks.\nThese extension members are defined within the global namespace, so they can be used on the corresponding types just like intrinsic members, without any additional `using` directives.\n\nFor example, with **PolyShim** you can reference the `Environment.ProcessId` static property (added in .NET 5.0) on any version of .NET:\n\n```csharp\nusing System;\n\n// On newer frameworks, this references the framework-provided property.\n// On older frameworks, this references the polyfilled (extension) property.\n// Same code works everywhere without any changes.\nvar processId = Environment.ProcessId;\n```\n\n\u003e [!NOTE]\n\u003e You can find the full list of member polyfills [here](Signatures.md).\n\n### Unsafe code\n\nCertain polyfills that implement low-level memory manipulation features (e.g. `Span\u003cT\u003e.ctor(void*, int)`) require unsafe code to work.\nBecause **PolyShim** is a source-only package, unsafe code needs to be enabled in your project if you wish to use those polyfills.\nTo do that, set the `\u003cAllowUnsafeBlocks\u003e` property to `true`:\n\n```xml\n\u003cProject\u003e\n\n  \u003cPropertyGroup\u003e\n    \u003cTargetFramework\u003enetstandard2.0\u003c/TargetFramework\u003e\n\n    \u003c!-- Enable unsafe code for polyfills that require it --\u003e\n    \u003cAllowUnsafeBlocks\u003etrue\u003c/AllowUnsafeBlocks\u003e\n  \u003c/PropertyGroup\u003e\n\n  \u003cItemGroup\u003e\n    \u003cPackageReference Include=\"PolyShim\" Version=\"...\" /\u003e\n  \u003c/ItemGroup\u003e\n\n\u003c/Project\u003e\n```\n\nFor example, with unsafe code enabled, you can use stack-allocated span initialization on any version of .NET:\n\n```csharp\nSpan\u003cbyte\u003e buffer = stackalloc byte[256];\n```\n\n### Compatibility packages\n\nSome features from newer versions of .NET can also be made available on older frameworks using official compatibility packages published by Microsoft.\n**PolyShim** automatically detects if any of these packages are installed and adjusts its polyfill coverage accordingly — either by enabling additional polyfills that build upon those features, or by disabling polyfills for APIs that are already provided in the compatibility packages.\n\nCurrently, **PolyShim** recognizes the following packages:\n\n- [`System.Diagnostics.Process`](https://nuget.org/packages/System.Diagnostics.Process) — `Process`, `ProcessStartInfo`, etc.\n- [`System.Management`](https://nuget.org/packages/System.Management) — `ManagementObjectSearcher`, etc.\n- [`System.Memory`](https://nuget.org/packages/System.Memory) — `Memory\u003cT\u003e`, `Span\u003cT\u003e`, etc.\n- [`System.Net.Http`](https://nuget.org/packages/System.Net.Http) — `HttpClient`, `HttpContent`, etc.\n- [`System.Runtime.InteropServices.RuntimeInformation`](https://nuget.org/packages/System.Runtime.InteropServices.RuntimeInformation) — `RuntimeInformation`, `OSPlatform`, etc.\n- [`System.Threading.Tasks`](https://nuget.org/packages/System.Threading.Tasks) — `Task`, `Task\u003cT\u003e`, etc.\n- [`System.Threading.Tasks.Extensions`](https://nuget.org/packages/System.Threading.Tasks.Extensions) — `ValueTask`, `ValueTask\u003cT\u003e`, etc.\n- [`System.ValueTuple`](https://nuget.org/packages/System.ValueTuple) — `ValueTuple\u003c...\u003e`, etc.\n- [`Microsoft.Bcl.Async`](https://nuget.org/packages/Microsoft.Bcl.Async) — `Task`, `Task\u003cT\u003e`, etc. (wider support than the `System.*` variant).\n- [`Microsoft.Bcl.AsyncInterfaces`](https://nuget.org/packages/Microsoft.Bcl.AsyncInterfaces) — `IAsyncEnumerable\u003cT\u003e`, `IAsyncDisposable`, etc.\n- [`Microsoft.Bcl.HashCode`](https://nuget.org/packages/Microsoft.Bcl.HashCode) — `HashCode`, etc.\n- [`Microsoft.Bcl.Memory`](https://nuget.org/packages/Microsoft.Bcl.Memory) — `Index`, `Range`, etc.\n- [`Microsoft.Bcl.TimeProvider`](https://nuget.org/packages/Microsoft.Bcl.TimeProvider) — `TimeProvider`, `ITimer`, etc.\n- [`Microsoft.Net.Http`](https://nuget.org/packages/Microsoft.Net.Http) — `HttpClient`, `HttpContent`, etc. (wider support than the `System.*` variant).\n\nFor example, adding a reference to the `Microsoft.Bcl.AsyncInterfaces` package will enable **PolyShim**'s polyfills that work with `IAsyncEnumerable\u003cT\u003e`, such as `Task.WhenEach(...)`:\n\n```xml\n\u003cProject\u003e\n\n  \u003cPropertyGroup\u003e\n    \u003cTargetFramework\u003enetstandard2.0\u003c/TargetFramework\u003e\n  \u003c/PropertyGroup\u003e\n\n  \u003cItemGroup\u003e\n    \u003cPackageReference Include=\"PolyShim\" Version=\"...\" /\u003e\n    \u003cPackageReference Include=\"Microsoft.Bcl.AsyncInterfaces\" Version=\"...\" /\u003e\n  \u003c/ItemGroup\u003e\n\n\u003c/Project\u003e\n```\n\n```csharp\nusing System;\nusing System.Linq;\nusing System.Threading.Tasks;\n\nvar tasks = Enumerable.Range(1, 10).Select(async i =\u003e\n{\n    await Task.Delay(Random.Shared.Next(1000));\n    return i * i;\n});\n\n// Microsoft.Bcl.AsyncInterfaces is referenced, so this polyfill is enabled\nawait foreach (var completedTask in Task.WhenEach(tasks))\n{\n    Console.WriteLine(await completedTask);\n}\n```\n\nConversely, adding a reference to the `System.Memory` package will disable **PolyShim**'s own versions of `Span\u003cT\u003e` and `Memory\u003cT\u003e`.\nYou can leverage this to prioritize the official implementation wherever possible, while still benefiting from other polyfills provided by **PolyShim**:\n\n```xml\n\u003cProject\u003e\n\n  \u003cPropertyGroup\u003e\n    \u003cTargetFramework\u003enetstandard2.0\u003c/TargetFramework\u003e\n  \u003c/PropertyGroup\u003e\n\n  \u003cItemGroup\u003e\n    \u003cPackageReference Include=\"PolyShim\" Version=\"...\" /\u003e\n    \u003cPackageReference Include=\"System.Memory\" Version=\"...\" /\u003e\n  \u003c/ItemGroup\u003e\n\n\u003c/Project\u003e\n```\n\n```csharp\nusing System.Buffers;\n\n// System.Memory is referenced, so this polyfill is disabled\n// (the official MemoryPool\u003cT\u003e is used instead)\nusing var buffer = MemoryPool\u003cbyte\u003e.Shared.Rent(1024);\nvar memory = buffer.Memory.Slice(0, 1024);\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftyrrrz%2Fpolyshim","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftyrrrz%2Fpolyshim","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftyrrrz%2Fpolyshim/lists"}