Skip to content

Commit

Permalink
Event flattening
Browse files Browse the repository at this point in the history
  • Loading branch information
JLChnToZ committed Jun 4, 2023
1 parent 45e095a commit 2a3e315
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 2 deletions.
4 changes: 2 additions & 2 deletions JLChnToZ.CommonUtils.Dynamic/LimitlessEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg
targetDelegate = argDelegate;
else {
// Rewrap delegate to avoid type mismatch
targetDelegate = Delegate.CreateDelegate(eventType, argDelegate, delegateType.GetMethod("Invoke"), false);
if (targetDelegate == null) { // Failed to rewrap, possibly incorrect signature
targetDelegate = argDelegate.ConvertAndFlatten(eventType);
if (targetDelegate == null) {
result = null;
return false;
}
Expand Down
35 changes: 35 additions & 0 deletions JLChnToZ.CommonUtils.Dynamic/Utilites.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;

Expand Down Expand Up @@ -105,6 +106,40 @@ public static MethodInfo GetUndelyRaiseMethod(this EventInfo eventInfo, out Dele
}
return raiseMethod;
}

public static Delegate ConvertAndFlatten(this Delegate del, Type toType = null) {
if (del == null) return null;
if (toType == null) toType = del.GetType();
var entries = new Stack<Delegate>();
entries.Push(del);
del = null;
while (entries.Count > 0) {
var current = entries.Pop();
if (current == null) continue;
// Check if current delegate multi-cast and if so, flatten it
var list = current.GetInvocationList();
if (list.Length > 1) {
// We do it in reverse order to preserve the order of the delegates
for (int i = list.Length - 1; i >= 0; i--)
entries.Push(list[i]);
continue;
}
var target = current.Target;
var method = current.Method;
// Check if target is a delegate and if so, flatten it
if (target is Delegate subDelegate && method.Name == "Invoke") {
list = subDelegate.GetInvocationList();
for (int i = list.Length - 1; i >= 0; i--)
entries.Push(list[i]);
continue;
}
if (current.GetType() != toType)
current = target == null ? Delegate.CreateDelegate(toType, method, false) :
Delegate.CreateDelegate(toType, target, method, false);
del = Delegate.Combine(del, current);
}
return del;
}
}

internal enum MethodMatchLevel {
Expand Down

0 comments on commit 2a3e315

Please sign in to comment.