openlang

The using declaration refactor moves Dispose past Publish()

Shorter syntax, longer lifetime. A C# using declaration disposes its variable at the end of the scope it's declared in, and that scope is easy to miss when the refactor looks like a tidy-up.

Take a method that acquires input in a using block that sits directly in the method body, calls Read(input), leaves the block, then calls Publish(). The editor offers to turn the block into a using declaration at method scope. Accept it and Publish() now runs before input is disposed. If Publish() throws, disposal happens as control leaves the method. In the original version it had already happened.

The editor recognized the pattern correctly. Whether this method should hold the resource across Publish() is another question, and the preview gives no hint of it. All it shows is braces going away and indentation shifting.

So what should it mark, so that someone accepting the change can see the scope moved?

后续讨论 6

顺着彼此的依据读下去
  1. 固定链接

    Highlight Publish() as a statement that now runs before disposal. Recognizing the syntax is the easy part, and it tells the editor nothing about whether this method can live with the longer lifetime.

  2. 固定链接

    Highlighting it is a start. It gets more interesting if Publish() is only allowed after input has been disposed. The method-scope rewrite breaks that rule, and the text change still looks completely routine.

    Try one more candidate edit. Keep the original inner block and put the using declaration inside it, so disposal still happens at the end of that block. Offer it as its own option, with the affected statements visible in the preview. The choice that actually matters is which scope to keep, and a preview of deleted braces says very little about that.

  3. 固定链接

    Careful with what that marker promises. It can say when Dispose will run. It can't say every consumer of input has finished.

    What if Read(input) keeps a reference to input somewhere that outlives the call, a field or a background task? Then the original block has the same question, refactor or not. Flag the escaping reference when the tool can see one, and keep the refactor decision about disposal scope.

  4. 固定链接

    Here's the version that makes the preview harder. Make input an IAsyncDisposable and the block becomes await using. Disposal is now an awaited DisposeAsync at the end of the scope, so moving the scope moves an await too. In a method that also awaits Publish(), the method-scope rewrite puts Publish() before the dispose and changes where the method yields. If the code uses ConfigureAwait(false), the dispose can also end up running on a different thread than before. None of that shows in a diff of deleted braces. The preview should say "disposal moves past these awaits", in those words.

  5. 固定链接

    Visual Basic never got the declaration form, so this refactor cannot even be offered there. Using input As New StreamReader(path) and End Using is the only spelling, and the scope is always written down. For someone reading the code for the first time I count that as a small kindness.

  6. 固定链接

    mtsuda's candidate keeps the old order. Give Dispose a line to write and Publish() another, and the three versions come apart. The original block prints read, dispose, publish. The method-scope declaration prints read, publish, dispose. mtsuda's version, the declaration inside an explicit inner block, prints read, dispose, publish again, same as the original.

    So the shorter syntax and the old lifetime can live together. An extra block might help here after all, and it's the one candidate where the preview would have nothing to warn about.

同一个问题的其他角度

  1. My function returns an array when all I asked for was a path

    Writing a PowerShell function from scratch for once (rather than squinting at someone else's), and it misbehaves in a way I c…

    回复 4最近活动 powershell
  2. My init set fill-column for exactly one buffer

    Had (setq fill-column 72) in my init for ages and only just noticed that M-q in a fresh buffer still wraps at 70. (In *scratc…

    回复 8最近活动 emacs-lisp
  3. Upgradeable means the storage layout is forever

    People hear proxy pattern and think the immutability problem went away. It moved. The proxy holds the state and forwards call…

    回复 3最近活动 solidity