Closed
Description
Background and Motivation
Currently,we have an API to invocation list of MulticastDelegate,it is MulticastDelegate.GetInvocationList().
It allocates array every time we call it.
And maybe that's why we have internal HasSingleTarget property in it.
We need handsome,and performant API.
Proposed API
public class Delegate
{
// Existing API
// public virtual System.Delegate[] GetInvocationList();
// Returns whether the delegate has a single target. It is a property to highlight that it is guaranteed
// to be a very cheap operation that is important for set of scenarios addressed by this proposal.
// Alternative names: HasSingleTarget, IsTrueMulticast (inverted condition), HasSingleElementInvocationList
public bool IsSingle { get; }
// Returns length of the invocation list. It is a method to highlight that it may not be a very cheap operation.
// This method is optional part of the proposal for completeness. It is fine to omit it from the approved shape.
public int GetInvocationListLength();
// Returns invocation list enumerator
public static InvocationListEnumerator<TDelegate> EnumerateInvocationList<TDelegate>(TDelegate d) where TDelegate : Delegate;
// The shape of this enumerator matches existing StringBuilder.ChunkEnumerator and Activity.Enumerator
// Neither of these existing enumerators implement IEnumerable and IEnumerator. This can be changed.
// Q: How are we deciding whether enumerators like this should implement IEnumerable and IEnumerator?
// Note that implementing these interfaces makes each instantiation of the type more expensive, so it is a tradeoff.
public struct InvocationListEnumerator<TDelegate> where TDelegate : Delegate
{
public TDelegate Current { get; }
public bool MoveNext();
// EditorBrowsable to match existing StringBuilder.ChunkEnumerator and Activity.Enumerator
[EditorBrowsable(EditorBrowsableState.Never)] // Only here to make foreach work
public InvocationListEnumerator<TDelegate> GetEnumerator() => this;
}
}
Original rejected proposal
public ReadOnlySpan<Delegate> InvocationList => delegates == null ? MemoryMarshal.CreateSpan(this,1) : delegates;