From ad546adafe7b61a6182c4ff132f86893be3040db Mon Sep 17 00:00:00 2001 From: Christian <6939810+chkr1011@users.noreply.github.com> Date: Wed, 3 Aug 2022 20:27:53 +0200 Subject: [PATCH] Fix removal of event handlers from async event. --- .github/workflows/ReleaseNotes.md | 1 + MQTTnet.sln.DotSettings | 6 +- .../Internal/AsyncEvent_Tests.cs | 66 +++++++++++++++++++ .../MQTTnet/Internal/AsyncEventInvocator.cs | 6 +- 4 files changed, 74 insertions(+), 5 deletions(-) create mode 100644 Source/MQTTnet.Tests/Internal/AsyncEvent_Tests.cs diff --git a/.github/workflows/ReleaseNotes.md b/.github/workflows/ReleaseNotes.md index 883446ea..72eb8188 100644 --- a/.github/workflows/ReleaseNotes.md +++ b/.github/workflows/ReleaseNotes.md @@ -1,3 +1,4 @@ +* [Core] Fixed not working removal of event handlers from async events (#1479). * [Client] Added support for passing the local endpoint (network card) which should be used (#1311). * [Client] Exposed _PackageIdentifier_ in _MqttApplicationMessageReceivedEventArgs_ (thanks to @koepalex, #1466). * [Server] Added a new event (_ClientAcknowledgedPublishPacketAsync_) which is fired whenever a client acknowledges a PUBLISH packet (QoS 1 and 2, #487). diff --git a/MQTTnet.sln.DotSettings b/MQTTnet.sln.DotSettings index 87d205d0..dfaffacc 100644 --- a/MQTTnet.sln.DotSettings +++ b/MQTTnet.sln.DotSettings @@ -226,9 +226,9 @@ </Entry> </TypePattern> </Patterns> - // Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. + Licensed to the .NET Foundation under one or more agreements. +The .NET Foundation licenses this file to you under the MIT license. +See the LICENSE file in the project root for more information. True True True diff --git a/Source/MQTTnet.Tests/Internal/AsyncEvent_Tests.cs b/Source/MQTTnet.Tests/Internal/AsyncEvent_Tests.cs new file mode 100644 index 00000000..3c1fdc90 --- /dev/null +++ b/Source/MQTTnet.Tests/Internal/AsyncEvent_Tests.cs @@ -0,0 +1,66 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using MQTTnet.Implementations; +using MQTTnet.Internal; + +namespace MQTTnet.Tests.Internal +{ + [TestClass] + public sealed class AsyncEvent_Tests + { + int _testEventAsyncCount; + + [TestMethod] + public async Task Attach_EventHandler() + { + var testClass = new TestClass(); + + testClass.TestEventAsync += OnTestEventAsync; + + await testClass.FireEventAsync(EventArgs.Empty); + + Assert.AreEqual(1, _testEventAsyncCount); + } + + [TestMethod] + public async Task Detach_EventHandler() + { + var testClass = new TestClass(); + + testClass.TestEventAsync += OnTestEventAsync; + testClass.TestEventAsync -= OnTestEventAsync; + + await testClass.FireEventAsync(EventArgs.Empty); + + Assert.AreEqual(0, _testEventAsyncCount); + } + + Task OnTestEventAsync(EventArgs arg) + { + Interlocked.Increment(ref _testEventAsyncCount); + return PlatformAbstractionLayer.CompletedTask; + } + + sealed class TestClass + { + readonly AsyncEvent _testEvent = new AsyncEvent(); + + public event Func TestEventAsync + { + add => _testEvent.AddHandler(value); + remove => _testEvent.RemoveHandler(value); + } + + public Task FireEventAsync(EventArgs eventArgs) + { + return _testEvent.InvokeAsync(eventArgs); + } + } + } +} \ No newline at end of file diff --git a/Source/MQTTnet/Internal/AsyncEventInvocator.cs b/Source/MQTTnet/Internal/AsyncEventInvocator.cs index 55541837..6258b28b 100644 --- a/Source/MQTTnet/Internal/AsyncEventInvocator.cs +++ b/Source/MQTTnet/Internal/AsyncEventInvocator.cs @@ -21,12 +21,14 @@ namespace MQTTnet.Internal public bool WrapsHandler(Action handler) { - return ReferenceEquals(_handler, handler); + // Do not use ReferenceEquals! It will not work with delegates. + return handler == _handler; } public bool WrapsHandler(Func handler) { - return ReferenceEquals(_asyncHandler, handler); + // Do not use ReferenceEquals! It will not work with delegates. + return handler == _asyncHandler; } public Task InvokeAsync(TEventArgs eventArgs)