Three obvious options:
1) Derive from a base class which defines the event, and declare your extension method to take an instance of that base class.
abstract class ManagerBase
{
public event EventHandler Changed;
protected void OnChanged()
{
Changed?.Invoke(this, EventArgs.Empty);
}
}
class A : ManagerBase { ... }
class B : ManagerBase { ... }
class C : ManagerBase { ... }
...
public static Task ToTask(this ManagerBase manager) { ... }
2) Implement an interface which defines the event, and declare your extension method to take an instance of that interface:
interface IManager
{
event EventHandler Changed;
}
class A : IManager
{
public event EventHandler Changed;
private void OnChanged()
{
Changed?.Invoke(this, EventArgs.Empty);
}
...
}
...
public static Task ToTask(this IManager manager) { ... }
3) Pass in the methods to attach and detach the event handler as actions:
public static Task ToTask<T>(this T manager, Action<T, EventHandler> addHandler, Action<T, EventHandler> removeHandler)
{
var taskCompletionSource = new TaskCompletionSource<bool>(TaskCreationOptions.AttachedToParent);
EventHandler onChanged = null;
onChanged = (sender, args) =>
{
removeHandler((T)sender, onChanged);
taskCompletionSource.TrySetResult(true);
};
addHandler(manager, onChanged);
return taskCompletionSource.Task;
}