Release transport references in Dispose regardless of _shouldDispose#2586
Merged
Conversation
Copilot
AI
changed the title
[WIP] Fix dispose not handled correctly in device code
Release transport references in Dispose regardless of Jul 1, 2026
_shouldDispose
raffaeler
approved these changes
Jul 1, 2026
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates multiple .NET IoT device bindings to always release (set to null/null!) transport/controller fields during Dispose, even when the transport is caller-owned (_shouldDispose == false), reducing unnecessary object rooting and improving GC behavior.
Changes:
- Moved transport/controller field null-assignment outside the
_shouldDisposeguard across many bindings. - Adjusted
if/else-dispose patterns (close pins when caller-owned) so null-assignment happens after the last field use. - Standardized the pattern across I2C/SPI/GPIO/serial-based bindings and a few shared helper types.
Reviewed changes
Copilot reviewed 40 out of 40 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/devices/Vl53L0X/Vl53L0X.cs | Always clears _i2cDevice reference after guarded disposal. |
| src/devices/Uln2003/Uln2003.cs | Always clears _controller reference after guarded disposal. |
| src/devices/Tcs3472x/Tcs3472x.cs | Always clears _i2cDevice reference after guarded disposal. |
| src/devices/Tca955x/Tca955x.cs | Clears _controller reference outside _shouldDispose guard (but Dispose(bool) needs a fix; see PR comment). |
| src/devices/Ssd1351/Ssd1351.cs | Clears _gpioDevice reference outside _shouldDispose guard. |
| src/devices/SoftwareSpi/SoftwareSpi.cs | Clears _gpioController reference outside _shouldDispose guard. |
| src/devices/SoftPwm/SoftwarePwmChannel.cs | Clears _controller reference outside _shouldDispose guard. |
| src/devices/ShiftRegister/ShiftRegister.cs | Clears _controller reference outside _shouldDispose guard. |
| src/devices/PiJuice/PiJuice.cs | Always clears _i2cDevice reference after guarded disposal. |
| src/devices/Pcd8544/Pcd8544.cs | Clears _controller reference after if/else that may close pins. |
| src/devices/Pca95x4/Pca95x4.cs | Always clears _controller reference after guarded disposal. |
| src/devices/Nrf24l01/Nrf24l01.cs | Always clears _gpio reference after guarded disposal. |
| src/devices/Mpu6xxx9xxx/Mpu9250.cs | Always clears _i2cDevice reference after guarded disposal. |
| src/devices/Mhz19b/Mhz19b.cs | Always clears _serialPortStream reference after guarded disposal. |
| src/devices/Mfrc522/Mfrc522.cs | Always clears _controller reference after guarded disposal. |
| src/devices/Mcp25xxx/Mcp25xxx.cs | Always clears _gpioController reference after guarded disposal. |
| src/devices/Mcp23xxx/Mcp23xxx.cs | Always clears _controller and _bus references after guarded disposal. |
| src/devices/LiquidLevel/LiquidLevelSwitch.cs | Always clears _controller reference after guarded disposal. |
| src/devices/LidarLiteV3/LidarLiteV3.cs | Always clears _gpioController reference after guarded disposal. |
| src/devices/KeyMatrix/KeyMatrix.cs | Clears _gpioController reference after if/else that may close pins. |
| src/devices/Ht1632/Ht1632.cs | Always clears _controller reference after guarded disposal. |
| src/devices/Hcsr501/Hcsr501.cs | Always clears _controller reference after guarded disposal. |
| src/devices/Hcsr04/Hcsr04.cs | Always clears _controller reference after guarded disposal. |
| src/devices/GrovePi/GrovePi.cs | Always clears _i2cDevice reference after guarded disposal. |
| src/devices/ExplorerHat/Motors.cs | Always clears _controller reference after guarded disposal. |
| src/devices/ExplorerHat/Lights.cs | Always clears _controller reference after guarded disposal. |
| src/devices/ExplorerHat/Led.cs | Always clears _controller reference after guarded disposal. |
| src/devices/ExplorerHat/ExplorerHat.cs | Always clears _controller reference after guarded disposal. |
| src/devices/Dhtxx/DhtBase.cs | Clears _controller reference after if/else that may close pin. |
| src/devices/DCMotor/DCMotor.cs | Always clears Controller reference after guarded disposal. |
| src/devices/Common/Iot/Device/Multiplexing/GpioOutputSegment.cs | Always clears _controller reference after guarded disposal. |
| src/devices/Charlieplex/CharlieplexSegment.cs | Always clears _gpioController reference after guarded disposal. |
| src/devices/CharacterLcd/LcdInterface.Gpio.cs | Always clears _controller reference after guarded disposal. |
| src/devices/Ccs811/Ccs811Sensor.cs | Clears _controller reference after if/else that may close pins. |
| src/devices/Button/GpioButton.cs | Clears _gpioController reference after if/else that may close the pin. |
| src/devices/Bno055/Bno055Sensor.cs | Always clears _i2cDevice reference after guarded disposal. |
| src/devices/Bmm150/Bmm150.cs | Always clears _i2cDevice reference after guarded disposal. |
| src/devices/Blinkt/Blinkt.cs | Always clears _gpioController reference after guarded disposal. |
| src/devices/Ak8963/Ak8963.cs | Always clears _i2cDevice reference after guarded disposal. |
| src/devices/Ads1115/Ads1115.cs | Always clears _gpioController reference after guarded disposal. |
Comment on lines
+662
to
666
| _controller = null; | ||
|
|
||
| _busDevice?.Dispose(); | ||
|
|
||
| base.Dispose(true); |
krwq
approved these changes
Jul 2, 2026
Contributor
Author
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.
Fixes: #1971
Device bindings placed the field
= null/= null!assignment inside theif (_shouldDispose)guard inDispose. When the transport is caller-owned (_shouldDispose == false), the binding never cleared its reference, keeping the object rooted longer than necessary.Changes
_shouldDisposeguard across 40 device bindings — theDispose()call stays guarded (caller-owned transports are not disposed), but the reference is always cleared.else-branch cases (GpioButton,Ccs811,Dhtxx,KeyMatrix,Pcd8544) — the branch closes pins on caller-owned controllers, so the null assignment is placed after the wholeif/elseblock, past the last use of the field.Notes
autoDispose → shouldDisposerename raised in the discussion is already complete in the codebase; the broader "missing null assignment" cases and the analyzer idea (Code-gen shouldDispose ctor and Dispose pattern #1971) are left as follow-ups.