Kenneth J. Sanchez Venegas 推荐的反射是获取类外事件调用列表的唯一方法。但是当性能很重要时,我们可以像这样使用已编译的 lambdas 创建一个助手:
public class EventHelper<TClass, TDelegate> where TDelegate : Delegate
{
public EventHelper(string eventName)
{
var fieldInfo = typeof(TClass).GetField(eventName, BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance) ??
throw new ArgumentException("Event was not found", nameof(eventName));
var thisArg = Expression.Parameter(typeof(TClass));
var body = Expression.Convert(Expression.Field(thisArg, fieldInfo), typeof(TDelegate));
Get = Expression.Lambda<Func<TClass, TDelegate?>>(body, thisArg).Compile();
}
public Func<TClass, TDelegate?> Get { get; }
public IEnumerable<TDelegate> GetInvocationList(TClass forInstance)
{
var eventDelegate = Get(forInstance);
if (eventDelegate is null)
yield break;
foreach (var d in eventDelegate.GetInvocationList())
yield return (TDelegate)d;
}
}
假设我们将有一个这个助手的实例并且每次都使用它:
private static readonly EventHelper<JsonSerializer, EventHandler<ErrorEventArgs>> _errorHelper = new(nameof(JsonSerializer.Error));
...
JsonSerializerSettings settings = new();
foreach (var errorHandler in _errorHelper.GetInvocationList(serializer))
settings.Error += errorHandler;
...
*我正在使用此代码从 Json.NET JsonSerializer 中提取设置,因此示例取自该上下文
**使用 C# 9.0 语法特性的代码示例,在 .NET 5 和 .NET 6 上测试。