蓝牙BLE订阅Adafruit板Notify功能时触发System.ObjectDisposedException异常求助
Let’s break down your issue and walk through the most likely causes and fixes—this is a common gotcha with BLE in C#, so you’re not alone here.
First, the core of that System.ObjectDisposedException ("The object has been closed") is straightforward: the BLE object you’re trying to interact with (like a GattCharacteristic, GattDescriptor, or even the underlying connection session) has already been disposed of or marked as closed when you attempt to write the Client Characteristic Configuration Descriptor (CCCD) to enable Notify.
Let’s address your specific questions first:
Does the board continuously writing data cause this?
No, the board actively sending Notify data won’t directly trigger this exception. However, if your code accidentally disposes of BLE objects while handling incoming data (e.g., you callDispose()on the characteristic in a value-changed callback), that would lead to this error if you try to reconfigure Notify later.Do I have to write the CCCD before the board starts writing data?
Not necessarily—but you do need to write the CCCD while the characteristic, service, and BLE connection are still active. If the board is already sending data, that means Notify was already enabled at some point. If you’re seeing this exception when trying to re-enable Notify, it’s likely the underlying objects were released in the meantime.
Most Common Root Causes & Fixes
1. Poor Object Lifecycle Management
C# BLE APIs (like those in Windows.Devices.Bluetooth.GenericAttributeProfile) rely heavily on object references staying alive. If you declare GattCharacteristic or GattDeviceService as local variables (e.g., inside a method that exits quickly), the garbage collector might dispose of them before you can interact with them.
Fix:
- Declare your BLE objects (characteristic, service, session) as class-level fields instead of local variables. This keeps them in scope for the lifetime of your connection.
- Avoid calling
Dispose()on these objects until you’re completely done with the connection (e.g., when the user explicitly disconnects the device).
2. Out-of-Order Async Operations
BLE operations are asynchronous, and if you try to write the CCCD before the connection is fully established, or before the characteristic is successfully retrieved, you might end up operating on a partially initialized (or already disposed) object.
Fix:
- Always
awaitasynchronous BLE operations (likeGetCharacteristicsAsync()orConnectAsync()) before proceeding to write the CCCD. - Check the connection status (
GattDeviceService.ConnectionStatus) before any operation to ensure the device is still connected.
3. Accidental Disposal in Callbacks
It’s easy to accidentally dispose of BLE objects in the ValueChanged callback (where you handle incoming data). For example, if you have cleanup logic that runs when data stops coming in, it might dispose of the characteristic prematurely.
Fix:
- Never dispose of BLE objects inside the
ValueChangedcallback. Handle cleanup only when you intentionally disconnect the device. - If you need to stop receiving data, disable Notify by writing the "disable" value to the CCCD instead of disposing the characteristic.
4. Unexpected Connection Drops
If the BLE connection drops (e.g., the board goes out of range, loses power) before you write the CCCD, the underlying GattSession will be closed, and any operations on related objects will throw this exception.
Fix:
- Register for the
GattDeviceService.ConnectionStatusChangedevent to detect when the connection drops. Pause or retry operations only when the connection is active. - Add error handling around the CCCD write operation to catch this exception and trigger a reconnection flow if needed.
Quick Code Example to Avoid the Exception
Here’s a simplified snippet that follows best practices:
// Class-level fields to keep BLE objects alive private GattCharacteristic _notifyChar; private GattDeviceService _deviceService; private async Task EnableNotifySafely() { // Guard clauses to ensure valid state if (_deviceService?.ConnectionStatus != GattConnectionStatus.Connected) { Console.WriteLine("Device not connected—can't enable Notify"); return; } if (_notifyChar == null) { // Re-fetch the characteristic if it's null (e.g., after reconnection) var chars = await _deviceService.GetCharacteristicsAsync(); _notifyChar = chars.Characteristics.FirstOrDefault(c => c.Uuid == YOUR_NOTIFY_CHAR_UUID); if (_notifyChar == null) { Console.WriteLine("Notify characteristic not found"); return; } } // Get the CCCD descriptor var cccd = _notifyChar.GetDescriptors(GattDescriptorUuids.ClientCharacteristicConfiguration).FirstOrDefault(); if (cccd == null) { Console.WriteLine("CCCD descriptor missing"); return; } try { // Write to enable Notify await cccd.WriteValueAsync(GattCharacteristicNotificationValue.EnableNotification); // Register for data updates _notifyChar.ValueChanged += OnNotifyDataReceived; } catch (ObjectDisposedException ex) { Console.WriteLine($"Failed to enable Notify: {ex.Message}"); // Trigger reconnection or re-fetch objects here } } private void OnNotifyDataReceived(GattCharacteristic sender, GattValueChangedEventArgs args) { // Process incoming data—don't dispose of sender here! var data = args.CharacteristicValue; // Your data handling logic... }
内容的提问来源于stack exchange,提问作者valegians

