This repository has been archived by the owner on Jun 11, 2021. It is now read-only.
forked from dotnet/dotNext
-
Notifications
You must be signed in to change notification settings - Fork 1
/
DelegateHelpers.Utils.cs
42 lines (35 loc) · 1.64 KB
/
DelegateHelpers.Utils.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
using System;
using System.Runtime.InteropServices;
namespace DotNext
{
public static partial class DelegateHelpers
{
[StructLayout(LayoutKind.Auto)]
private readonly struct TargetRewriter : ISupplier<Delegate, object?>
{
private readonly object target;
internal TargetRewriter(object newTarget) => target = newTarget;
object? ISupplier<Delegate, object?>.Invoke(Delegate d) => target;
}
[StructLayout(LayoutKind.Auto)]
private readonly struct EmptyTargetRewriter : ISupplier<Delegate, object?>
{
object? ISupplier<Delegate, object?>.Invoke(Delegate d) => d.Target;
}
private static TDelegate ChangeType<TDelegate, TRewriter>(this Delegate d, TRewriter rewriter)
where TDelegate : Delegate
where TRewriter : struct, ISupplier<Delegate, object?>
{
var list = d.GetInvocationList();
if (list.LongLength == 1L)
return ReferenceEquals(list[0], d) ? d.Method.CreateDelegate<TDelegate>(rewriter.Invoke(d)) : ChangeType<TDelegate, TRewriter>(list[0], rewriter);
// We use untyped CreateDelegate to avoid typecast inside of the loop.
// Also, it's reasonable to reuse already allocated invocation list to store
// newly created delegates because Delegate.Combine accepts array only
var delegateType = typeof(TDelegate);
foreach (ref var sub in list.AsSpan())
sub = sub.Method.CreateDelegate(delegateType, rewriter.Invoke(sub));
return (TDelegate)Delegate.Combine(list)!;
}
}
}