diff --git a/apiCount.include.md b/apiCount.include.md index daf25ed..22c0cf3 100644 --- a/apiCount.include.md +++ b/apiCount.include.md @@ -1 +1 @@ -**API count: 434** \ No newline at end of file +**API count: 435** \ No newline at end of file diff --git a/api_list.include.md b/api_list.include.md index 151ddc5..5f52819 100644 --- a/api_list.include.md +++ b/api_list.include.md @@ -490,6 +490,11 @@ * `bool TryParse(string?, IFormatProvider?, byte)` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.byte.tryparse#system-byte-tryparse(system-string-system-iformatprovider-system-byte@)) +#### DelegatePolyfill + + * `InvocationListEnumerator EnumerateInvocationList(TDelegate?) where TDelegate : Delegate` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.delegate.enumerateinvocationlist) + + #### GuidPolyfill * `Guid CreateVersion7()` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.guid.createversion7#system-guid-createversion7) diff --git a/readme.md b/readme.md index 7e67999..ca1127d 100644 --- a/readme.md +++ b/readme.md @@ -12,7 +12,7 @@ The package targets `netstandard2.0` and is designed to support the following ru * `net5.0`, `net6.0`, `net7.0`, `net8.0`, `net9.0` -**API count: 434** +**API count: 435** **See [Milestones](../../milestones?state=closed) for release notes.** @@ -959,6 +959,11 @@ The class `Polyfill` includes the following extension methods: * `bool TryParse(string?, IFormatProvider?, byte)` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.byte.tryparse#system-byte-tryparse(system-string-system-iformatprovider-system-byte@)) +#### DelegatePolyfill + + * `InvocationListEnumerator EnumerateInvocationList(TDelegate?) where TDelegate : Delegate` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.delegate.enumerateinvocationlist) + + #### GuidPolyfill * `Guid CreateVersion7()` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.guid.createversion7#system-guid-createversion7) diff --git a/src/ApiBuilderTests/BuildApiTest.cs b/src/ApiBuilderTests/BuildApiTest.cs index 64f95b1..36e0f8b 100644 --- a/src/ApiBuilderTests/BuildApiTest.cs +++ b/src/ApiBuilderTests/BuildApiTest.cs @@ -34,6 +34,7 @@ public void RunWithRoslyn() WriteHelper(types, "RegexPolyfill", writer, ref count); WriteHelper(types, "StringPolyfill", writer, ref count); WriteHelper(types, "BytePolyfill", writer, ref count); + WriteHelper(types, "DelegatePolyfill", writer, ref count); WriteHelper(types, "GuidPolyfill", writer, ref count); WriteHelper(types, "DateTimePolyfill", writer, ref count); WriteHelper(types, "DateTimeOffsetPolyfill", writer, ref count); diff --git a/src/Polyfill/DelegatePolyfill.cs b/src/Polyfill/DelegatePolyfill.cs new file mode 100644 index 0000000..5a75f81 --- /dev/null +++ b/src/Polyfill/DelegatePolyfill.cs @@ -0,0 +1,65 @@ +// + + +#pragma warning disable + +namespace Polyfills; + +using System; +using System.ComponentModel; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; + +[ExcludeFromCodeCoverage] +[DebuggerNonUserCode] +#if PolyPublic +public +#endif +static partial class DelegatePolyfill +{ + /// + /// Gets an enumerator for the invocation targets of this delegate. + /// + //Link: https://learn.microsoft.com/en-us/dotnet/api/system.delegate.enumerateinvocationlist +#if NET9_0_OR_GREATER + public static Delegate.InvocationListEnumerator EnumerateInvocationList(TDelegate? target) where TDelegate : Delegate => + Delegate.EnumerateInvocationList(target); +#else + public static InvocationListEnumerator EnumerateInvocationList(TDelegate? target) where TDelegate : Delegate => + new InvocationListEnumerator(target); + + /// + /// Provides an enumerator for the invocation list of a delegate. + /// + /// Delegate type being enumerated. + public struct InvocationListEnumerator + where TDelegate : Delegate + { + Delegate[] delegates; + int index = -1; + + internal InvocationListEnumerator(Delegate target) => + delegates = target.GetInvocationList(); + + public TDelegate Current { get; private set; } + + public bool MoveNext() + { + int index = this.index + 1; + if (index == delegates.Length) + { + return false; + } + + Current = (TDelegate) delegates[index]; + this.index = index; + return true; + } + + [EditorBrowsable(EditorBrowsableState.Never)] + public InvocationListEnumerator GetEnumerator() => this; + } +#endif + +} \ No newline at end of file diff --git a/src/Tests/PolyfillTests_Delegate.cs b/src/Tests/PolyfillTests_Delegate.cs index 55fa753..7966f76 100644 --- a/src/Tests/PolyfillTests_Delegate.cs +++ b/src/Tests/PolyfillTests_Delegate.cs @@ -1,14 +1,14 @@ partial class PolyfillTests { - public static event EventHandler? MyEvent; + public static event EventHandler? EventForHasSingleTarget; [Test] public void HasSingleTarget() { - MyEvent += Handler; - Assert.IsTrue(MyEvent.HasSingleTarget()); - MyEvent += Handler; - Assert.IsFalse(MyEvent.HasSingleTarget()); + EventForHasSingleTarget += Handler; + Assert.IsTrue(EventForHasSingleTarget.HasSingleTarget()); + EventForHasSingleTarget += Handler; + Assert.IsFalse(EventForHasSingleTarget.HasSingleTarget()); var action = () => { }; @@ -20,4 +20,21 @@ public void HasSingleTarget() static void Handler(object? sender, EventArgs e) { } + + public static event EventHandler? EventForEnumerateInvocationList; + + [Test] + public void EnumerateInvocationList() + { + var count = 0; + + EventForEnumerateInvocationList += (_, _) => count++; + + foreach (var item in DelegatePolyfill.EnumerateInvocationList(EventForEnumerateInvocationList)) + { + item(this, EventArgs.Empty); + } + + Assert.AreEqual(1, count); + } } \ No newline at end of file