From b5a9c87973bcef1ce34b06770b76297e74562f27 Mon Sep 17 00:00:00 2001 From: Damian Suess Date: Mon, 11 May 2026 08:44:51 -0400 Subject: [PATCH 1/3] Rename WaitForPropertyValueInternalAsync to WaitForPropertyValueAsync and make public --- .../Extensions/WatchableExtensions.cs | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/Linux.Bluetooth/Extensions/WatchableExtensions.cs b/src/Linux.Bluetooth/Extensions/WatchableExtensions.cs index 8dd2a81..5887802 100644 --- a/src/Linux.Bluetooth/Extensions/WatchableExtensions.cs +++ b/src/Linux.Bluetooth/Extensions/WatchableExtensions.cs @@ -17,7 +17,7 @@ public static class WatchableExtensions /// Task or exception. /// On timeout a is thrown. public static Task WaitForPropertyValueAsync(this IAdapter1 obj, string propertyName, T value, TimeSpan timeout) - => WaitForPropertyValueInternalAsync(obj.GetAsync, obj.WatchPropertiesAsync, propertyName, value, timeout); + => WaitForPropertyValueAsync(obj.GetAsync, obj.WatchPropertiesAsync, propertyName, value, timeout); /// Wait for AdvertisingManager's Property and specified value to resolve. /// Type of value. @@ -28,7 +28,7 @@ public static Task WaitForPropertyValueAsync(this IAdapter1 obj, string prope /// Task or exception. /// On timeout a is thrown. public static Task WaitForPropertyValueAsync(this ILEAdvertisingManager1 obj, string propertyName, T value, TimeSpan timeout) - => WaitForPropertyValueInternalAsync(obj.GetAsync, obj.WatchPropertiesAsync, propertyName, value, timeout); + => WaitForPropertyValueAsync(obj.GetAsync, obj.WatchPropertiesAsync, propertyName, value, timeout); /// Wait for Device's Property and specified value to resolve. /// Type of value. @@ -39,7 +39,7 @@ public static Task WaitForPropertyValueAsync(this ILEAdvertisingManager1 obj, /// Task or exception. /// On timeout a is thrown. public static Task WaitForPropertyValueAsync(this IDevice1 obj, string propertyName, T value, TimeSpan timeout) - => WaitForPropertyValueInternalAsync(obj.GetAsync, obj.WatchPropertiesAsync, propertyName, value, timeout); + => WaitForPropertyValueAsync(obj.GetAsync, obj.WatchPropertiesAsync, propertyName, value, timeout); /// Wait for Battery's Property and specified value to resolve. /// Type of value. @@ -50,7 +50,7 @@ public static Task WaitForPropertyValueAsync(this IDevice1 obj, string proper /// Task or exception. /// On timeout a is thrown. public static Task WaitForPropertyValueAsync(this IBattery1 obj, string propertyName, T value, TimeSpan timeout) - => WaitForPropertyValueInternalAsync(obj.GetAsync, obj.WatchPropertiesAsync, propertyName, value, timeout); + => WaitForPropertyValueAsync(obj.GetAsync, obj.WatchPropertiesAsync, propertyName, value, timeout); /* /// Wait for GattService's Property and specified value to resolve. @@ -62,7 +62,7 @@ public static Task WaitForPropertyValueAsync(this IBattery1 obj, string prope /// Task or exception. /// On timeout a is thrown. public static Task WaitForPropertyValueAsync(this IGattService1 obj, string propertyName, T value, TimeSpan timeout) - => WaitForPropertyValueInternalAsync(obj.GetAsync, obj.WatchPropertiesAsync, propertyName, value, timeout); + => WaitForPropertyValueAsync(obj.GetAsync, obj.WatchPropertiesAsync, propertyName, value, timeout); /// Wait for GattCharacteristic's Property and specified value to resolve. /// Type of value. @@ -73,7 +73,7 @@ public static Task WaitForPropertyValueAsync(this IGattService1 obj, string p /// Task or exception. /// On timeout a is thrown. public static Task WaitForPropertyValueAsync(this IGattCharacteristic1 obj, string propertyName, T value, TimeSpan timeout) - => WaitForPropertyValueInternalAsync(obj.GetAsync, obj.WatchPropertiesAsync, propertyName, value, timeout); + => WaitForPropertyValueAsync(obj.GetAsync, obj.WatchPropertiesAsync, propertyName, value, timeout); /// Wait for GattDescriptor's Property and specified value to resolve. /// Type of value. @@ -84,7 +84,7 @@ public static Task WaitForPropertyValueAsync(this IGattCharacteristic1 obj, s /// Task or exception. /// On timeout a is thrown. public static Task WaitForPropertyValueAsync(this IGattDescriptor1 obj, string propertyName, T value, TimeSpan timeout) - => WaitForPropertyValueInternalAsync(obj.GetAsync, obj.WatchPropertiesAsync, propertyName, value, timeout); + => WaitForPropertyValueAsync(obj.GetAsync, obj.WatchPropertiesAsync, propertyName, value, timeout); */ /// Wait for MediaControl's Property and specified value to resolve. @@ -96,7 +96,7 @@ public static Task WaitForPropertyValueAsync(this IGattDescriptor1 obj, strin /// Task or exception. /// On timeout a is thrown. public static Task WaitForPropertyValueAsync(this IMediaControl1 obj, string propertyName, T value, TimeSpan timeout) - => WaitForPropertyValueInternalAsync(obj.GetAsync, obj.WatchPropertiesAsync, propertyName, value, timeout); + => WaitForPropertyValueAsync(obj.GetAsync, obj.WatchPropertiesAsync, propertyName, value, timeout); /// /// Wait for watchable objects property and specified value to resolve. @@ -110,10 +110,13 @@ public static Task WaitForPropertyValueAsync(this IMediaControl1 obj, string /// TimeSpan to wait for. /// Task or exception. /// On timeout a is thrown. - private static async Task WaitForPropertyValueInternalAsync( + public static async Task WaitForPropertyValueAsync( Func> getAsync, - Func, Task> watchPropertiesAsync, - string propertyName, T value, TimeSpan timeout) + Func, + Task> watchPropertiesAsync, + string propertyName, + T value, + TimeSpan timeout) { // TODO: Change to Task versus throwing an error. var (watchTask, watcher) = WaitForPropertyValueInternal(watchPropertiesAsync, propertyName, value); From aefa48668580928f6bbb91e35975c7b6a44391de Mon Sep 17 00:00:00 2001 From: Valentin Kindschi Date: Mon, 13 Apr 2026 16:17:27 +0200 Subject: [PATCH 2/3] fix: Fixed library warnings --- src/Linux.Bluetooth/Adapter.cs | 50 +++++++++++-------- src/Linux.Bluetooth/BlueZManager.cs | 8 +-- src/Linux.Bluetooth/CloseSafeHandle.cs | 40 --------------- src/Linux.Bluetooth/DBusInterfaces.cs | 4 ++ src/Linux.Bluetooth/Device.cs | 44 +++++++++------- src/Linux.Bluetooth/GattCharacteristic.cs | 33 ++++++------ .../GattServer/GattApplication.cs | 6 ++- .../Models/AdapterProperties.cs | 34 +++++++------ 8 files changed, 103 insertions(+), 116 deletions(-) delete mode 100644 src/Linux.Bluetooth/CloseSafeHandle.cs diff --git a/src/Linux.Bluetooth/Adapter.cs b/src/Linux.Bluetooth/Adapter.cs index 35cd9ef..072440d 100644 --- a/src/Linux.Bluetooth/Adapter.cs +++ b/src/Linux.Bluetooth/Adapter.cs @@ -16,12 +16,17 @@ namespace Linux.Bluetooth /// public class Adapter : IAdapter1, IDisposable { - private IAdapter1 _proxy; - private IDisposable _interfacesWatcher; - private IDisposable _propertyWatcher; - private DeviceChangeEventHandlerAsync _deviceFound; - private AdapterEventHandlerAsync _poweredOn; - private IObjectManager _objectManager; + private IAdapter1? _proxy; + private IDisposable? _interfacesWatcher; + private IDisposable? _propertyWatcher; + private DeviceChangeEventHandlerAsync? _deviceFound; + private AdapterEventHandlerAsync? _poweredOn; + private IObjectManager? _objectManager; + + private IAdapter1 Proxy => _proxy ?? throw new InvalidOperationException("Adapter has not been initialized."); + + private IObjectManager ObjectManager => + _objectManager ?? throw new InvalidOperationException("Adapter object manager has not been initialized."); ~Adapter() { @@ -35,8 +40,9 @@ internal static async Task CreateAsync(IAdapter1 proxy) _proxy = proxy, }; - adapter._objectManager = Connection.System.CreateProxy(BluezConstants.DbusService, "/"); - adapter._interfacesWatcher = await adapter._objectManager.WatchInterfacesAddedAsync(adapter.OnDeviceAddedAsync); + var objectManager = Connection.System.CreateProxy(BluezConstants.DbusService, "/"); + adapter._objectManager = objectManager; + adapter._interfacesWatcher = await objectManager.WatchInterfacesAddedAsync(adapter.OnDeviceAddedAsync); adapter._propertyWatcher = await proxy.WatchPropertiesAsync(adapter.OnPropertyChanges); return adapter; @@ -78,19 +84,19 @@ public event AdapterEventHandlerAsync PoweredOn } } - public event AdapterEventHandlerAsync PoweredOff; + public event AdapterEventHandlerAsync? PoweredOff; /// See also, Name, property. - public ObjectPath ObjectPath => _proxy.ObjectPath; + public ObjectPath ObjectPath => Proxy.ObjectPath; public Task GetAllAsync() { - return _proxy.GetAllAsync(); + return Proxy.GetAllAsync(); } public async Task GetPropertiesAsync() { - var p = await _proxy.GetAllAsync(); + var p = await Proxy.GetAllAsync(); return new AdapterProperties { @@ -121,7 +127,7 @@ public async Task GetPropertiesAsync() /// public Task GetAsync(string prop) { - return _proxy.GetAsync(prop); + return Proxy.GetAsync(prop); } /// @@ -132,12 +138,12 @@ public Task GetAsync(string prop) /// String of filters. public Task GetDiscoveryFiltersAsync() { - return _proxy.GetDiscoveryFiltersAsync(); + return Proxy.GetDiscoveryFiltersAsync(); } public Task RemoveDeviceAsync(ObjectPath Device) { - return _proxy.RemoveDeviceAsync(Device); + return Proxy.RemoveDeviceAsync(Device); } /// Set Property Value Async. @@ -146,7 +152,7 @@ public Task RemoveDeviceAsync(ObjectPath Device) /// public Task SetAsync(string prop, object val) { - return _proxy.SetAsync(prop, val); + return Proxy.SetAsync(prop, val); } /// @@ -158,27 +164,27 @@ public Task SetAsync(string prop, object val) /// public Task SetDiscoveryFilterAsync(IDictionary properties) { - return _proxy.SetDiscoveryFilterAsync(properties); + return Proxy.SetDiscoveryFilterAsync(properties); } /// Scan for devices nearby. /// Task. public Task StartDiscoveryAsync() { - return _proxy.StartDiscoveryAsync(); + return Proxy.StartDiscoveryAsync(); } /// Stop scanning for devices nearby. /// Task. public Task StopDiscoveryAsync() { - return _proxy.StopDiscoveryAsync(); + return Proxy.StopDiscoveryAsync(); } public async Task> GetDevicesPathsAsync() { List result = new List(); - var objects = await _objectManager.GetManagedObjectsAsync(); + var objects = await ObjectManager.GetManagedObjectsAsync(); foreach (var path in objects.Keys) { var interfaces = objects[path]; @@ -199,7 +205,7 @@ public async Task> GetDevicesPathsAsync() /// Disposable task. public Task WatchPropertiesAsync(Action handler) { - return _proxy.WatchPropertiesAsync(handler); + return Proxy.WatchPropertiesAsync(handler); } private async void FireEventForExistingDevicesAsync() @@ -226,7 +232,7 @@ private async void FireEventIfPropertyAlreadyTrueAsync(AdapterEventHandlerAsync { try { - var value = await _proxy.GetAsync(prop); + var value = await Proxy.GetAsync(prop); if (value) { // TODO: Suppress duplicate event from OnPropertyChanges. diff --git a/src/Linux.Bluetooth/BlueZManager.cs b/src/Linux.Bluetooth/BlueZManager.cs index 8d0976e..11ab1ba 100644 --- a/src/Linux.Bluetooth/BlueZManager.cs +++ b/src/Linux.Bluetooth/BlueZManager.cs @@ -71,7 +71,7 @@ public static string NormalizeUUID(string uuid) /// The interface to search for /// The DBus object to search under. Can be null - internal static async Task> GetProxiesAsync(string interfaceName, IDBusObject rootObject) + internal static async Task> GetProxiesAsync(string interfaceName, IDBusObject? rootObject) { // Console.WriteLine("GetProxiesAsync called."); var objectManager = Connection.System.CreateProxy(BluezConstants.DbusService, "/"); @@ -89,12 +89,14 @@ internal static async Task> GetProxiesAsync(string interface return proxies; } - internal static bool IsMatch(string interfaceName, ObjectPath objectPath, IDictionary> interfaces, IDBusObject rootObject) + internal static bool IsMatch(string interfaceName, ObjectPath objectPath, + IDictionary> interfaces, IDBusObject? rootObject) { return IsMatch(interfaceName, objectPath, interfaces.Keys, rootObject); } - internal static bool IsMatch(string interfaceName, ObjectPath objectPath, ICollection interfaces, IDBusObject rootObject) + internal static bool IsMatch(string interfaceName, ObjectPath objectPath, ICollection interfaces, + IDBusObject? rootObject) { if (rootObject != null && !objectPath.ToString().StartsWith($"{rootObject.ObjectPath}/")) { diff --git a/src/Linux.Bluetooth/CloseSafeHandle.cs b/src/Linux.Bluetooth/CloseSafeHandle.cs deleted file mode 100644 index bd7e6b4..0000000 --- a/src/Linux.Bluetooth/CloseSafeHandle.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace Tmds.DBus; - -/// -/// Generic file descriptor SafeHandle. -/// -public class CloseSafeHandle : SafeHandle -{ - [DllImport("libc", SetLastError = true)] - internal static extern int close(int fd); - - /// - /// Creates a new CloseSafeHandle. - /// - /// An IntPtr object that represents the pre-existing handle to use. - /// true to reliably release the handle during the finalization phase; false to prevent reliable release. - public CloseSafeHandle(IntPtr preexistingHandle, bool ownsHandle) - : base(new IntPtr(-1), ownsHandle) - { - SetHandle(preexistingHandle); - } - - /// - /// Gets a value that indicates whether the handle is invalid. - /// - public override bool IsInvalid - { - get { return handle == new IntPtr(-1); } - } - - /// - /// When overridden in a derived class, executes the code required to free the handle. - /// - protected override bool ReleaseHandle() - { - return close(handle.ToInt32()) == 0; - } -} diff --git a/src/Linux.Bluetooth/DBusInterfaces.cs b/src/Linux.Bluetooth/DBusInterfaces.cs index 353a7ba..fa36361 100644 --- a/src/Linux.Bluetooth/DBusInterfaces.cs +++ b/src/Linux.Bluetooth/DBusInterfaces.cs @@ -2,6 +2,10 @@ // Bluetoothctl was used to connect to a Bluetooth Low Energy device, then `dotnet dbus codegen --bus system --service org.bluez` was executed. // After code generation, some `ObjectPath`s were manually replaced with the right interface types. // For more context, see https://developers.redhat.com/blog/2017/09/18/connecting-net-core-d-bus/ or https://github.com/tmds/Tmds.DBus +// +// The generator does not emit nullable annotations, so keep the generated surface +// as-is and handle nullability in the handwritten wrappers around it. +#nullable disable using System; using System.Collections.Generic; diff --git a/src/Linux.Bluetooth/Device.cs b/src/Linux.Bluetooth/Device.cs index cfd93b1..64298c9 100644 --- a/src/Linux.Bluetooth/Device.cs +++ b/src/Linux.Bluetooth/Device.cs @@ -17,12 +17,14 @@ public class Device : IDevice1, IDisposable private const string DeviceConnected = "Connected"; private const string DeviceServicesResolved = "ServicesResolved"; - private IDevice1 _proxy; - private IDisposable _propertyWatcher; + private IDevice1? _proxy; + private IDisposable? _propertyWatcher; - private event DeviceEventHandlerAsync OnConnected; + private event DeviceEventHandlerAsync? OnConnected; - private event DeviceEventHandlerAsync OnResolved; + private event DeviceEventHandlerAsync? OnResolved; + + private IDevice1 Proxy => _proxy ?? throw new InvalidOperationException("Device has not been initialized."); ~Device() { @@ -62,7 +64,7 @@ public event DeviceEventHandlerAsync Connected } } - public event DeviceEventHandlerAsync Disconnected; + public event DeviceEventHandlerAsync? Disconnected; public event DeviceEventHandlerAsync ServicesResolved { @@ -77,7 +79,7 @@ public event DeviceEventHandlerAsync ServicesResolved } } - public ObjectPath ObjectPath => _proxy.ObjectPath; + public ObjectPath ObjectPath => Proxy.ObjectPath; /// /// This method can be used to cancel a pairing operation initiated by the Pair method. @@ -90,7 +92,7 @@ public event DeviceEventHandlerAsync ServicesResolved /// Task. public Task CancelPairingAsync() { - return _proxy.CancelPairingAsync(); + return Proxy.CancelPairingAsync(); } /// @@ -101,7 +103,7 @@ public Task CancelPairingAsync() /// Task. public Task ConnectAsync() { - return _proxy.ConnectAsync(); + return Proxy.ConnectAsync(); } /// @@ -121,12 +123,12 @@ public Task ConnectAsync() /// public Task ConnectProfileAsync(string uuid) { - return _proxy.ConnectProfileAsync(uuid); + return Proxy.ConnectProfileAsync(uuid); } public Task DisconnectAsync() { - return _proxy.DisconnectAsync(); + return Proxy.DisconnectAsync(); } /// @@ -144,26 +146,26 @@ public Task DisconnectAsync() /// Task. public Task DisconnectProfileAsync(string uuid) { - return _proxy.DisconnectProfileAsync(uuid); + return Proxy.DisconnectProfileAsync(uuid); } /// Gets all properties for connected device. /// BlueZ . public Task GetAllAsync() { - return _proxy.GetAllAsync(); + return Proxy.GetAllAsync(); } public Task GetAsync(string prop) { - return _proxy.GetAsync(prop); + return Proxy.GetAsync(prop); } /// Gets all properties for device. /// object. public async Task GetPropertiesAsync() { - var p = await _proxy.GetAllAsync(); + var p = await Proxy.GetAllAsync(); var props = new DeviceProperties { @@ -173,7 +175,11 @@ public async Task GetPropertiesAsync() Appearance = p.Appearance, Blocked = p.Blocked, Class = p.Class, + // Keep populating the legacy DTO members while the preferred names remain + // available for newer callers. +#pragma warning disable CS0618 Connected = p.Connected, // Connected is marked for deprecation (2024-01-11) +#pragma warning restore CS0618 IsConnected = p.Connected, Icon = p.Icon, LegacyPairing = p.LegacyPairing, @@ -181,7 +187,9 @@ public async Task GetPropertiesAsync() Modalias = p.Modalias, Name = p.Name, Paired = p.Paired, +#pragma warning disable CS0618 RSSI = p.RSSI, // RSSI is marked for deprecation (2024-01-11) +#pragma warning restore CS0618 Rssi = p.RSSI, ServiceData = p.ServiceData, ServicesResolved = p.ServicesResolved, @@ -195,24 +203,24 @@ public async Task GetPropertiesAsync() public Task PairAsync() { - return _proxy.PairAsync(); + return Proxy.PairAsync(); } public Task SetAsync(string prop, object val) { - return _proxy.SetAsync(prop, val); + return Proxy.SetAsync(prop, val); } public Task WatchPropertiesAsync(Action handler) { - return _proxy.WatchPropertiesAsync(handler); + return Proxy.WatchPropertiesAsync(handler); } private async void FireEventIfPropertyAlreadyTrueAsync(DeviceEventHandlerAsync handler, string prop) { try { - var value = await _proxy.GetAsync(prop); + var value = await Proxy.GetAsync(prop); if (value) { // TODO: Suppress duplicate event from OnPropertyChanges. diff --git a/src/Linux.Bluetooth/GattCharacteristic.cs b/src/Linux.Bluetooth/GattCharacteristic.cs index d8518ec..c633e01 100644 --- a/src/Linux.Bluetooth/GattCharacteristic.cs +++ b/src/Linux.Bluetooth/GattCharacteristic.cs @@ -12,10 +12,13 @@ namespace Linux.Bluetooth /// public class GattCharacteristic : IGattCharacteristic1, IDisposable { - private IGattCharacteristic1 _proxy; - private IDisposable _propertyWatcher; + private IGattCharacteristic1? _proxy; + private IDisposable? _propertyWatcher; - private event GattCharacteristicEventHandlerAsync _onValue; + private event GattCharacteristicEventHandlerAsync? _onValue; + + private IGattCharacteristic1 Proxy => + _proxy ?? throw new InvalidOperationException("GATT characteristic has not been initialized."); ~GattCharacteristic() { @@ -57,63 +60,63 @@ public event GattCharacteristicEventHandlerAsync Value } } - public ObjectPath ObjectPath => _proxy.ObjectPath; + public ObjectPath ObjectPath => Proxy.ObjectPath; public Task ReadValueAsync(IDictionary Options) { - return _proxy.ReadValueAsync(Options); + return Proxy.ReadValueAsync(Options); } public Task WriteValueAsync(byte[] Value, IDictionary Options) { - return _proxy.WriteValueAsync(Value, Options); + return Proxy.WriteValueAsync(Value, Options); } public Task<(CloseSafeHandle fd, ushort mtu)> AcquireWriteAsync(IDictionary Options) { - return _proxy.AcquireWriteAsync(Options); + return Proxy.AcquireWriteAsync(Options); } public Task<(CloseSafeHandle fd, ushort mtu)> AcquireNotifyAsync(IDictionary Options) { - return _proxy.AcquireNotifyAsync(Options); + return Proxy.AcquireNotifyAsync(Options); } public Task StartNotifyAsync() { - return _proxy.StartNotifyAsync(); + return Proxy.StartNotifyAsync(); } public Task StopNotifyAsync() { - return _proxy.StopNotifyAsync(); + return Proxy.StopNotifyAsync(); } public Task GetAsync(string prop) { - return _proxy.GetAsync(prop); + return Proxy.GetAsync(prop); } public Task GetAllAsync() { - return _proxy.GetAllAsync(); + return Proxy.GetAllAsync(); } public Task SetAsync(string prop, object val) { - return _proxy.SetAsync(prop, val); + return Proxy.SetAsync(prop, val); } public Task WatchPropertiesAsync(Action handler) { - return _proxy.WatchPropertiesAsync(handler); + return Proxy.WatchPropertiesAsync(handler); } private async void Subscribe() { try { - await _proxy.StartNotifyAsync(); + await Proxy.StartNotifyAsync(); // Is there a way to check if a characteristic supports Read? // // Reading the current value will trigger OnPropertyChanges. diff --git a/src/Linux.Bluetooth/GattServer/GattApplication.cs b/src/Linux.Bluetooth/GattServer/GattApplication.cs index 6a3529e..c30c39a 100644 --- a/src/Linux.Bluetooth/GattServer/GattApplication.cs +++ b/src/Linux.Bluetooth/GattServer/GattApplication.cs @@ -36,13 +36,15 @@ public Task WatchInterfacesAddedAsync(Action<(ObjectPath @object, IDictionary> interfaces)> handler, Action onError = null) + public async Task WatchInterfacesAddedAsync(Action<(ObjectPath @object, + IDictionary> interfaces)> handler, Action? onError = null) { await Task.Yield(); return Task.CompletedTask; } - public async Task WatchInterfacesRemovedAsync(Action<(ObjectPath @object, string[] interfaces)> handler, Action onError = null) + public async Task WatchInterfacesRemovedAsync(Action<(ObjectPath @object, string[] interfaces)> handler, + Action? onError = null) { await Task.Yield(); return Task.CompletedTask; diff --git a/src/Linux.Bluetooth/Models/AdapterProperties.cs b/src/Linux.Bluetooth/Models/AdapterProperties.cs index 619eaa2..60f08d1 100644 --- a/src/Linux.Bluetooth/Models/AdapterProperties.cs +++ b/src/Linux.Bluetooth/Models/AdapterProperties.cs @@ -1,23 +1,25 @@ -namespace Linux.Bluetooth +using System; + +namespace Linux.Bluetooth { /// Wrapper for Adapter1Properties. public class AdapterProperties { - public string Address { get; set; } = default(string); + public string Address { get; set; } = string.Empty; /// /// The Bluetooth Address Type. For dual-mode and BR/EDR - /// only adapter this defaults to "public". Single mode LE - /// adapters may have either value. With privacy enabled - /// this contains type of Identity Address and not type of - /// address used for connection. - /// - /// Possible values: - /// * "public" - Public address - /// * "random" - Random address + /// only adapter this defaults to "public". Single mode LE + /// adapters may have either value. With privacy enabled + /// this contains type of Identity Address and not type of + /// address used for connection. + /// + /// Possible values: + /// * "public" - Public address + /// * "random" - Random address /// /// Read-only - public string AddressType { get; set; } = default(string); + public string AddressType { get; set; } = string.Empty; /// /// The Bluetooth system name (pretty hostname). @@ -27,7 +29,7 @@ public class AdapterProperties /// access to the pretty hostname configuration. /// /// Read-only. - public string Name { get; set; } = default(string); + public string Name { get; set; } = string.Empty; /// /// The Bluetooth friendly name. This value can be changed. @@ -47,7 +49,7 @@ public class AdapterProperties /// resort. /// /// Read-write. - public string Alias { get; set; } = default(string); + public string Alias { get; set; } = string.Empty; /// /// The Bluetooth class of device. @@ -97,7 +99,7 @@ public class AdapterProperties /// The discoverable timeout in seconds.A value of zero /// means that the timeout is disabled and it will stay in /// discoverable/limited mode forever. - /// + /// /// The default value for the discoverable timeout should /// be 180 seconds(3 minutes). /// @@ -136,11 +138,11 @@ public class AdapterProperties /// List of 128-bit UUIDs that represents the available local services. /// Read-only. - public string[] UUIDs { get; set; } = default(string[]); + public string[] UUIDs { get; set; } = Array.Empty(); /// Local device ID information in mod alias format used by the kernal and udev. /// Readonly, optional. - public string Modalias { get; set; } = default(string); + public string Modalias { get; set; } = string.Empty; // Optional: /////// From 53b371054638d3db29d2c1dcdfe50b1584f88e63 Mon Sep 17 00:00:00 2001 From: Valentin Kindschi Date: Wed, 20 May 2026 15:54:31 +0200 Subject: [PATCH 3/3] fix: a nullable variable should have a '?'-suffixed type --- src/Linux.Bluetooth/Extensions/WatchableExtensions.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Linux.Bluetooth/Extensions/WatchableExtensions.cs b/src/Linux.Bluetooth/Extensions/WatchableExtensions.cs index 5887802..9c61ee8 100644 --- a/src/Linux.Bluetooth/Extensions/WatchableExtensions.cs +++ b/src/Linux.Bluetooth/Extensions/WatchableExtensions.cs @@ -149,7 +149,7 @@ private static (Task, IDisposable) WaitForPropertyValueInternal(Func(); - IDisposable watcher = null; + IDisposable? watcher = null; watcher = watchPropertiesAsync(propertyChanges => { try @@ -161,7 +161,7 @@ private static (Task, IDisposable) WaitForPropertyValueInternal(Func(Func