{"id":13629373,"url":"https://github.com/zompinc/sync-method-generator","last_synced_at":"2026-01-14T06:33:37.320Z","repository":{"id":62062259,"uuid":"556778572","full_name":"zompinc/sync-method-generator","owner":"zompinc","description":"Generates a synchronized version of an async method","archived":false,"fork":false,"pushed_at":"2025-12-24T19:38:41.000Z","size":382,"stargazers_count":75,"open_issues_count":17,"forks_count":7,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-12-26T09:44:03.434Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/zompinc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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}},"created_at":"2022-10-24T13:52:32.000Z","updated_at":"2025-12-24T19:12:23.000Z","dependencies_parsed_at":"2023-02-14T05:01:22.418Z","dependency_job_id":"f332e91f-2231-4eae-82cb-ba7d883fde28","html_url":"https://github.com/zompinc/sync-method-generator","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/zompinc/sync-method-generator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zompinc%2Fsync-method-generator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zompinc%2Fsync-method-generator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zompinc%2Fsync-method-generator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zompinc%2Fsync-method-generator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zompinc","download_url":"https://codeload.github.com/zompinc/sync-method-generator/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zompinc%2Fsync-method-generator/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28412211,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T05:26:33.345Z","status":"ssl_error","status_checked_at":"2026-01-14T05:21:57.251Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: 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":[],"created_at":"2024-08-01T22:01:08.784Z","updated_at":"2026-01-14T06:33:37.314Z","avatar_url":"https://github.com/zompinc.png","language":"C#","readme":"# Sync Method Generator\r\n\r\n![Type less, sync more, star!](https://img.shields.io/badge/Type_less-Sync_more-purple)\r\n[![Build](https://github.com/zompinc/sync-method-generator/actions/workflows/build.yml/badge.svg)](https://github.com/zompinc/sync-method-generator/actions/workflows/build.yml)\r\n![Support .NET Standard 2.0](https://img.shields.io/badge/dotnet%20version-.NET%20Standard%202.0-blue)\r\n[![Nuget](https://img.shields.io/nuget/v/Zomp.SyncMethodGenerator)](https://www.nuget.org/packages/Zomp.SyncMethodGenerator)\r\n[![codecov](https://codecov.io/gh/zompinc/sync-method-generator/branch/master/graph/badge.svg)](https://codecov.io/gh/zompinc/sync-method-generator)\r\n[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/zompinc/sync-method-generator)\r\n\r\nThis [.NET source generator](https://learn.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/source-generators-overview) produces a sync method from an async one.\r\n\r\n[⭐ Star this project](https://github.com/zompinc/sync-method-generator/stargazers) if you hate code duplication or calling async methods from sync.\r\n\r\n## Use cases\r\n\r\n- A library which exposes both sync and async version of a method\r\n- An application has to process two kinds of data in the same way:\r\n  - Large data from I/O which cannot be stored in memory before processing: Original async method\r\n  - Small sample of data in memory, usually a sample of the larger data: Generated sync method\r\n\r\n## How it works\r\n\r\n### CreateSyncVersionAttribute on a method\r\n\r\nDecorate your async method with `CreateSyncVersionAttribute` in your `partial` class, struct, record, or interface:\r\n\r\n```cs\r\n[Zomp.SyncMethodGenerator.CreateSyncVersion]\r\nstatic async Task WriteAsync(ReadOnlyMemory\u003cbyte\u003e buffer, Stream stream, \r\nCancellationToken ct)\r\n    =\u003e await stream.WriteAsync(buffer, ct).ConfigureAwait(true);\r\n```\r\n\r\nand it will generate a sync version of the method:\r\n\r\n```cs\r\nstatic void Write(ReadOnlySpan\u003cbyte\u003e buffer, Stream stream)\r\n    =\u003e stream.Write(buffer);\r\n```\r\n\r\nA list of changes applied to the new synchronized method:\r\n\r\n- Remove `async` modifier\r\n- Remove `await` from methods as well as `foreach` statement\r\n- Change types\r\n\r\n  | From                                                                                                                                                                                                | To                                                                                                                                   |\r\n  | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |\r\n  | [Task](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task)*                                                                                                                   | void                                                                                                                                 |\r\n  | [Task\\\u003cT\u003e](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task-1)                                                                                                              | T                                                                                                                                    |\r\n  | [Func](https://learn.microsoft.com/en-us/dotnet/api/system.func-1)\\\u003cTask\u003e                                                                                                                           | [Action](https://learn.microsoft.com/en-us/dotnet/api/system.action)                                                                 |\r\n  | Func\\\u003cTask\\\u003cT\u003e\u003e                                                                                                                                                                                     | Func\\\u003cT\u003e                                                                                                                             |\r\n  | [IAsyncEnumerable\\\u003cT\u003e](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.iasyncenumerable-1)                                                                                  | [IEnumerable\\\u003cT\u003e](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.ienumerable-1)                             |\r\n  | [IAsyncEnumerator\\\u003cT\u003e](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.iasyncenumerator-1)                                                                                  | [IEnumerator\\\u003cT\u003e](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.ienumerator-1)                             |\r\n  | [ConfiguredCancelableAsyncEnumerable\\\u003cT\u003e.Enumerator](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.configuredcancelableasyncenumerable-1.enumerator)                 | [IEnumerator\\\u003cT\u003e](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.ienumerator-1)                             |\r\n  | [ConfiguredCancelableAsyncEnumerable\\\u003cT\u003e.GetAsyncEnumerator](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.configuredcancelableasyncenumerable-1.getasyncenumerator) | [IEnumerable\\\u003cT\u003e.GetEnumerator](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.ienumerable-1.getenumerator) |\r\n  | [Memory\\\u003cT\u003e](https://learn.microsoft.com/en-us/dotnet/api/system.memory-1)**                                                                                                                        | [Span\\\u003cT\u003e](https://learn.microsoft.com/en-us/dotnet/api/system.span-1)                                                               |\r\n  | [ReadOnlyMemory\\\u003cT\u003e](https://learn.microsoft.com/en-us/dotnet/api/system.readonlymemory-1)**                                                                                                        | [ReadOnlySpan\\\u003cT\u003e](https://learn.microsoft.com/en-us/dotnet/api/system.readonlyspan-1)                                               |\r\n\r\n  \\* [ValueTask](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.valuetask)s are handled exactly like [Task](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task)s\r\n\r\n  \\*\\* `Memory` and `ReadOnlyMemory` is preserved in sync methods if it is a type argument of a collection. This is due to a compiler limitation which states that a `ref struct` can't be the element type of an array.\r\n\r\n- Remove parameters\r\n  - [CancellationToken](https://learn.microsoft.com/en-us/dotnet/api/system.threading.cancellationtoken)\r\n  - [IProgress\\\u003cT\u003e](https://learn.microsoft.com/en-us/dotnet/api/system.iprogress-1), unless the `PreserveProgress` property is set to `true`.\r\n- Invocation changes\r\n  - Remove `ConfigureAwait` from [Tasks](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.configureawait) and [Asynchronous Enumerations](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskasyncenumerableextensions.configureawait)\r\n  - Remove standalone `ConfigureAwait` statements\r\n  - Remove `WaitAsync` from [Tasks](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.waitasync)\r\n  - Remove [WithCancellation](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskasyncenumerableextensions.withcancellation)\r\n  - Rewrite asynchronous invocations with `Async` suffix to call synchronous version (e.g. [MoveNextAsync()](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.iasyncenumerator-1.movenextasync) becomes [MoveNext()](https://learn.microsoft.com/en-us/dotnet/api/system.collections.ienumerator.movenext))\r\n  - Remove asynchronous invocations without the `Async` suffix\r\n  - Remove [CancellationToken](https://learn.microsoft.com/en-us/dotnet/api/system.threading.cancellationtoken) parameter\r\n  - Remove [IProgress\\\u003cT\u003e.Report(T)](https://learn.microsoft.com/en-us/dotnet/api/system.iprogress-1.report) call\r\n  - Remove [Memory\\\u003cT\u003e.Span](https://learn.microsoft.com/en-us/dotnet/api/system.memory-1.span) property\r\n  - Change `await` [Task\\\u003cTResult\u003e.FromResult](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.fromresult)(`value`) to `value`\r\n  - Change `await` [Task.Delay](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.delay)(`value`) to [Thread.Sleep](https://learn.microsoft.com/en-us/dotnet/api/system.threading.thread.sleep)(`value`)\r\n  - Change any invocation returning [ConfiguredCancelableAsyncEnumerable\\\u003cT\u003e](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.configuredcancelableasyncenumerable-1) to [IEnumerable.GetEnumerator](https://learn.microsoft.com/en-us/dotnet/api/system.collections.ienumerable.getenumerator)()\r\n- Remove `CreateSyncVersionAttribute`\r\n- Update XML documentation\r\n\r\n#### Properties\r\n\r\n##### OmitNullableDirective\r\n\r\nThis source generator detects language version during the compilation. By default it will generate `#nullable enable` directive if and only if the language version is 8 or above. Since it is [impossible](https://github.com/dotnet/roslyn/issues/49555) to reliably determine whether nullable context is turned on or not, `OmitNullableDirective` property is available to omit that directive from generating.\r\n\r\n```cs\r\n[Zomp.SyncMethodGenerator.CreateSyncVersion(OmitNullableDirective = true)]\r\npublic async Task MethodAsync()\r\n{\r\n    string f = null;\r\n}\r\n```\r\n\r\n#### PreserveProgress\r\n\r\nBy default, this source generator removes `IProgress\u003cT\u003e` parameters from async methods. To preserve them, use the `PreserveProgress` option.\r\n\r\n```cs\r\n[Zomp.SyncMethodGenerator.CreateSyncVersion(PreserveProgress = true)]\r\npublic async Task MethodAsync(IProgress\u003cdouble\u003e progress)\r\n{\r\n    progress.Report(0.0);\r\n}\r\n```\r\n\r\n### CreateSyncVersionAttribute on a type\r\n\r\nYou can also decorate your type (class, struct, record, or interface) to generate a sync version for every asynchronous method.\r\n\r\n```cs\r\n[Zomp.SyncMethodGenerator.CreateSyncVersion]\r\npartial class MyClass {\r\n    async Task Method1Async(...) { ... }\r\n    async IAsyncEnumerable\u003c...\u003e Method2Async(...) { ... }\r\n    [Zomp.SyncMethodGenerator.SkipSyncVersion]\r\n    async Task WillNotGenerateAsync(...) { ... }\r\n}\r\n```\r\n\r\nThis will generate their sync counterparts:\r\n\r\n```cs\r\n[Zomp.SyncMethodGenerator.CreateSyncVersion]\r\npartial class MyClass {\r\n    void Method1(...) { ... }\r\n}\r\n```\r\n\r\nand\r\n\r\n```cs\r\n[Zomp.SyncMethodGenerator.CreateSyncVersion]\r\npartial class MyClass {\r\n    IEnumerable\u003c...\u003e Method2(...) { ... }\r\n}\r\n```\r\n\r\n#### SkipSyncVersionAttribute\r\n\r\nTo exclude a method from generating a sync version use `SkipSyncVersionAttribute` on a method. See `WillNotGenerateAsync` method in the example above.\r\n\r\n### SYNC_ONLY symbol\r\n\r\nIn case there is logic which should only be executed in the synchronized version of the method, wrap it in `SYNC_ONLY` #if directive.\r\n\r\n`SYNC_ONLY` must not be defined anywhere. The source generator will scan #if directives for this symbol.\r\n\r\nCode inside `SYNC_ONLY` block will be copied as is. Unless global namespaces are used in the project, this code should contain fully qualified namespaces.\r\n\r\nThe following syntax:\r\n\r\n```cs\r\n[Zomp.SyncMethodGenerator.CreateSyncVersion]\r\npublic async Task WithSyncOnlyDirectiveAsync(CancellationToken ct)\r\n{\r\n#if SYNC_ONLY\r\n    System.Console.Write(\"Sync\");\r\n#endif\r\n    await Task.CompletedTask;\r\n}\r\n```\r\n\r\nwill output:\r\n\r\n```cs\r\npublic void WithSyncOnlyDirective()\r\n{\r\n    System.Console.Write(\"Sync\");\r\n}\r\n```\r\n\r\nIf you only want to execute in the original async version, flip the flag like this: `#if !SYNC_ONLY`.\r\n\r\nNote: `SYNC_ONLY` cannot be mixed with other symbols in a conditional expression and cannot have `#elif` directive.\r\n\r\n\u003e [!WARNING]  \r\n\u003e `SYNC_ONLY` flag currently works in parameter lists, argument lists and statements.  \r\n\u003e Please always double check your code when using this flag.  \r\n\u003e If your use case is not supported, please log an issue.\r\n\r\n## Installation\r\n\r\nTo add the library use:\r\n\r\n```sh\r\ndotnet add package Zomp.SyncMethodGenerator\r\n```\r\n\r\n## Development\r\n\r\n### Related projects\r\n\r\n- [SyncToAsyncExtension](https://marketplace.visualstudio.com/items?itemName=lsoft.SyncToAsyncExtension) - Allows switching between sync and async versions of a method. Very useful in development of this library.\r\n\r\n### Act\r\n\r\nThis project is fully compatible with [act](https://github.com/nektos/act).\r\n\r\nOther than required packages to run `act` itself, GitHub Actions script installs anything else that might be missing, such as node, yarn and dotnet. On Windows platform, software installation is performed on the host itself due to [lack](https://github.com/nektos/act/issues/1608) of container support.\r\n\r\nTo build the project using act follow these instructions:\r\n\r\n#### Windows\r\n\r\nInstall [chocolatey](https://chocolatey.org/install) if missing.\r\n\r\nInstall the following packages if missing:\r\n\r\n```pwsh\r\nchoco install git -y\r\nchoco install act-cli -y\r\nrefreshenv\r\n```\r\n\r\nIn the project directory run:\r\n\r\n```pwsh\r\nact -P windows-latest=-self-hosted --artifact-server-path c:/tmp/artifacts\r\n```\r\n\r\n#### Linux\r\n\r\nInstall act by following these [instructions](https://lindevs.com/install-act-on-ubuntu).\r\n\r\nIn the project directory run:\r\n\r\n```pwsh\r\nact --artifact-server-path /tmp/artifacts\r\n```\r\n","funding_links":[],"categories":["Content","Source Generators","Recently Updated","Source Generator","Identifiers"],"sub_categories":["44. [SyncMethodGenerator](https://ignatandrei.github.io/RSCG_Examples/v2/docs/SyncMethodGenerator) , in the [EnhancementClass](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#enhancementclass) category","Other","[Jul 25, 2025](/content/2025/07/25/README.md)","GUI - other"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzompinc%2Fsync-method-generator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzompinc%2Fsync-method-generator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzompinc%2Fsync-method-generator/lists"}