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)