Generate ten synchronous SftpClient methods from their async versions - #1812
Open
virzak wants to merge 1 commit into
Open
Generate ten synchronous SftpClient methods from their async versions#1812virzak wants to merge 1 commit into
virzak wants to merge 1 commit into
Conversation
Ten of the synchronous methods on SftpClient are mechanical translations of the asynchronous ones beside them: the same argument checks, the same session calls with Async dropped, the same order. Each has been maintained by hand alongside its twin, and every fix to one has to be made to the other. Zomp.SyncMethodGenerator produces the synchronous version from the async source at compile time, into the same partial class, so the public API is unchanged. Verified method by method: each generated body is identical to the hand-written one it replaces, once the fully qualified names are reduced. The async methods now carry <inheritdoc /> where they previously repeated the interface documentation, which is what the twins already converted use, and the generated methods inherit the same documentation ISftpClient declares. Published documentation is unchanged. Left alone: RenameFile, whose async version does not have the isPosix overload the synchronous one routes through; and DownloadFile, UploadFile and ListDirectory, whose two versions genuinely differ. The generator is a build-time only dependency, so nothing is added to the package or to the runtime graph.
virzak
requested review from
Rob-Hague,
WojciechNagorski and
drieseng
as code owners
July 28, 2026 11:42
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this is
Ten of the synchronous methods on
SftpClientare mechanical translations of the asynchronous ones beside them - the same argument checks, the same session calls withAsyncdropped, the same order. Each is maintained by hand next to its twin, so every fix has to be made twice.This generates the synchronous version from the asynchronous source at compile time, into the same partial class. The public API is unchanged.
DeleteFileis representative:awaitis unwrapped,Taskbecomesvoid, the token parameter and the statements which only exist to observe it are dropped,GetCanonicalPathAsyncresolves toGetCanonicalPath, and what comes out is exactly theDeleteFilewhich is in the file today.Verification
I compared each generated method against the hand-written one it replaces, reducing the fully qualified names the generator emits. All ten are identical - not equivalent, identical. The methods are
ChangeDirectory,CreateDirectory,DeleteDirectory,DeleteFile,Get,Exists,GetStatus,Delete,Open(string, FileMode, FileAccess)andGetAttributes.dotnet build Renci.SshNet.slnx -c Release- clean, no new warnings, across all five target frameworksRenci.SshNet.Testson net10.0 - 2312 passed, 0 failed, 12 skippedTo read what is generated:
Documentation
The converted async methods now carry
<inheritdoc />where they previously repeated whatISftpClientalready declares. That is the patternDeleteFileAsyncandDeleteDirectoryAsyncalready use, and the generated synchronous methods inherit the same documentation from the interface. Published documentation is unchanged - worth stating plainly, since the docs site is built from these.Deliberately left alone
RenameFile- the synchronous version routes through anisPosixoverload which the async version has no equivalent of, so the two are not twins.DownloadFile,UploadFile,ListDirectory- these genuinely differ between the two versions rather than being translations.SftpSessionhas another 16 pairs in the same shape. I have not touched them; if this lands well, that is the obvious follow-up.About the dependency
Zomp.SyncMethodGenerator is a Roslyn source generator, referenced with
PrivateAssets="all", so it adds nothing to the shipped package or the runtime graph. SharpCompress adopted it earlier this week for the same reason.Disclosure: I maintain the generator. Two fixes went into it while preparing this PR - crefs in generated documentation not resolving, which would otherwise have been a build failure here, and argument list spacing. I am proposing this because the duplication in this file is exactly the case the tool handles, but if you would rather not take a build-time dependency, no hard feelings and I will close it.
🤖 Generated with Claude Code