Try this as your definition. Gotta love generics!
public static async Task WaitUntilAsync<T>(this Action action, Action<T> addHandler, Action<T> removeHandler, Predicate<string> pred) where T : class
Unfortunately, you cannot use delegates as generic constraints like so:
public static async Task WaitUntilAsync<T>(this Action action, Action<T> addHandler, Action<T> removeHandler, Predicate<string> pred) where T : EventHandler
...so you'll have to use reflection to confirm your type and then cast it manually.
Here is a complete example:
public static async Task WaitUntilAsync<TDelegate>(this Action action, Action<TDelegate> addHandler, Action<TDelegate> removeHandler, Predicate<string> pred) where TDelegate : class
{
var delegateType = typeof(TDelegate);
if (delegateType != typeof(EventHandler) && !delegateType.IsSubclassOf(typeof(EventHandler))) throw new Exception("TDelegate must be EventHandler or a subclass.");
var t = new TaskCompletionSource<bool>();
EventHandler realHandler = (sender, args) =>
{
//do real event work here
};
var handler = Delegate.CreateDelegate(delegateType, realHandler.Method) as TDelegate;
addHandler(handler);
action();
await t.Task;
removeHandler(handler);
}