【发布时间】:2023-01-10 04:20:08
【问题描述】:
我有一个类 BleScanner,它包装了一个内部 BluetoothLEAdvertisementWatcher。它还实现了 IDisposable 以确保在扫描仪被处理时停止观察者。
public sealed class BleScanner : IDisposable
{
public event AdvertisementReceivedHandler? AdvertisementReceived;
private readonly BluetoothLEAdvertisementWatcher m_Watcher;
public BleScanner() {
m_Watcher = new() {
// ...
};
// m_Watcher.Received += OnAdvertisementReceived;
}
// private void OnAdvertisementReceived(...) {
// code elided for brevity
// may eventually raise AdvertisementReceived
// }
public void Start() => m_Watcher.Start();
public void Stop() => m_Watcher.Stop();
public void Dispose() {
if (m_Watcher.Status == BluetoothLEAdvertisementWatcherStatus.Started) {
m_Watcher.Stop();
}
}
}
观察者不是一次性的。所以理论上,如果你在Dispose之后再次调用Start,扫描器仍然可以工作:
public async Task ScannerTest(CancellationToken token) {
using var scanner = new BleScanner();
scanner.AdvertisementReceived += OnAdvertisementReceived;
scanner.Start(); // will start the scan
await Task.Delay(3000, token); // raise events for 3 seconds
scanner.Stop(); // could be forgotten
scanner.Dispose(); // will stop the scan if indeed it was forgotten
scanner.Start(); // everything will work, despite "scanner" being disposed already
}
我是否应该确保Start(也许Stop)在Dispose被调用后抛出ObjectDisposedException? guidelines on the Dispose pattern 只要求Dispose 可以被调用多次而不会出现异常,但不说其他成员在Dispose 被调用后应该如何表现。 IDisposable interface 的 using disposable objects 也没有说明在已处置对象上调用方法时会发生什么。
【问题讨论】:
-
“观察者不是一次性的”- 为什么你的班级是
IDisposable? -“它还实现了 IDisposable 以确保在扫描仪被处理时停止观察者。”- 这不是实施IDisposable的好理由,imo。不过,我不能提出任何更好的建议,因为不幸的是 C# 不(还)支持线性类型。 -
意见可能会有所不同,但对我来说,如果您的实例不持有一次性物品,那么您就是在对班级的消费者施加人为约束。
-
但是要回答这个问题,IMO 如果它在罐头上写着
IDisposable,那么我会预计ObjectDisposedException如果它是在处理后使用的。 -
@Dai 但是,如果没有人想再使用结果,为什么观察者要继续占用 BLE 天线上的一个时隙进行扫描呢?
-
@LWChris 我同意你的看法:不应该——但这不是我的意思。我的观点是,我不认为
IDisposable一定是最好沟通方式合同要求给图书馆的消费者。也许如果您为您的class BleScanner分享一些示例用例,我们可以提出一些更好的建议。 (例如,短暂的单子行为可以更好地表示为Task(或Task<T>,如果它有有意义的结果)(这确实不是暗示也不要求使用async修饰符 BTW)。
标签: c# idisposable