如何编写扩展方法,使多播 C# 中的调用列表成员顺序委托 运行?
How to write extension method which will make invocation list members in multicast C# delegate run sequentially?
我有一个在异步方法中等待的异步委托:
async Task M1()
{
Debug.WriteLine("M1.A");
await Task.Delay(10);
Debug.WriteLine("M1.B");
}
async Task M2()
{
Debug.WriteLine("M2.A");
await Task.Delay(1);
Debug.WriteLine("M2.B");
}
delegate Task MyDel();
async void button_Click(object sender, RoutedEventArgs e)
{
MyDel del = null;
del += M1;
del += M2;
await del();
}
输出为:
M1.A
M2.A
M2.B
M1.B
也就是说,两个调用成员同时关闭,而不是等待对方。我需要他们互相等待,所以输出将是:
M1.A
M1.B
M2.A
M2.B
我试过用这个代替 await del()
:
foreach (MyDel member in del.GetInvocationList())
{
await member();
}
这行得通。但是,我有很多代码地方需要这样做。委托可以有不同数量的各种类型的参数,但它们都是 return Task
.
我如何编写一个扩展方法,让我通过这样的调用 运行 上面的代码?
del0.AwaitOneByOne(); // del0 is 'delegate Task Method()'
del1.AwaitOneByOne(paramInt1, paramStr2); // del1 is 'delegate Task Method(int, string)'
del2.AwaitOneByOne(paramBytes1); // del2 is 'delegate Task Method(byte[])'
如果您对委托使用 Func 而不是自定义委托,您可以这样写:
public static class FuncHelper
{
public static async Task RunSequential<T1>(this Func<T1,Task> del, T1 param1)
{
foreach (var d in del.GetInvocationList().OfType<Func<T1, Task>>())
{
await d(param1);
}
}
public static async Task RunSequential<T1, T2>(this Func<T1, T2, Task> del, T1 param1, T2 param2)
{
foreach (var d in del.GetInvocationList().OfType<Func<T1, T2, Task>>())
{
await d(param1, param2);
}
}
// Additional methods for more parameters go here
}
您似乎确实在尝试以非预期的方式使用委托。他们实际上不应该控制顺序或让功能相互依赖来完成。
制作自定义集合可能更好,如果您想要一些类似委托的行为,可以覆盖 += 和 -= 。
你的问题的原因是你的代表有一组不同的参数。
解决方案是创建一个额外的委托,其中包含包含参数的调用,类似于 System.Windows.Forms.MethodInvoker delegate。
您的 methodInvoker 的唯一区别是您的 methodInvoker 不是 returns 无效的委托,而是 returns 任务的委托。
您的扩展程序 class 中的函数与您的 foreach 类似:
public delegate task MethodInvoker();
static class DelegateExtensions
{
public static async Task ExecuteDelegates(this IEnumerable<MethodInvoker> methodInvokers)
{
foreach (var methodInvoker in methodInvokers)
{
await methodInvoker();
}
}
}
用法如下:
public MyClass
{
private async Task F1()
{
Debug.WriteLine("Begin F1");
await Task.Delay(TimeSpan.FromSeconds(1));
Debug.WriteLine("F1 Completed");
}
private async Task F2(TimeSpan waitTime)
{
Debug.WriteLine("Begin F2");
await Task.Delay(waitTime);
Debug.WriteLine("F2 Completed");
}
private async Task F3(int count, TimeSpan waitTime)
{
Debug.WriteLine("Begin F3");
for (int i = 0; i < count; ++i)
{
await Task.Delay(waitTime);
}
Debug.WriteLine("F3 Completed");
}
}
public async Task ExecuteMyFunctions()
{
MyClass X = new MyClass();
IEnumerable<MethodInvoker> myMethodInvokers = new MethodInvoker[]
{
() => X.F1(),
() => X.F2(TimeSpan.FromSeconds(1)),
() => X.F3(4, TimeSpan.FromSeconds(0.25)),
}
await myMethodInvokers.ExecuteDelegates();
}
我有一个在异步方法中等待的异步委托:
async Task M1()
{
Debug.WriteLine("M1.A");
await Task.Delay(10);
Debug.WriteLine("M1.B");
}
async Task M2()
{
Debug.WriteLine("M2.A");
await Task.Delay(1);
Debug.WriteLine("M2.B");
}
delegate Task MyDel();
async void button_Click(object sender, RoutedEventArgs e)
{
MyDel del = null;
del += M1;
del += M2;
await del();
}
输出为:
M1.A
M2.A
M2.B
M1.B
也就是说,两个调用成员同时关闭,而不是等待对方。我需要他们互相等待,所以输出将是:
M1.A
M1.B
M2.A
M2.B
我试过用这个代替 await del()
:
foreach (MyDel member in del.GetInvocationList())
{
await member();
}
这行得通。但是,我有很多代码地方需要这样做。委托可以有不同数量的各种类型的参数,但它们都是 return Task
.
我如何编写一个扩展方法,让我通过这样的调用 运行 上面的代码?
del0.AwaitOneByOne(); // del0 is 'delegate Task Method()'
del1.AwaitOneByOne(paramInt1, paramStr2); // del1 is 'delegate Task Method(int, string)'
del2.AwaitOneByOne(paramBytes1); // del2 is 'delegate Task Method(byte[])'
如果您对委托使用 Func 而不是自定义委托,您可以这样写:
public static class FuncHelper
{
public static async Task RunSequential<T1>(this Func<T1,Task> del, T1 param1)
{
foreach (var d in del.GetInvocationList().OfType<Func<T1, Task>>())
{
await d(param1);
}
}
public static async Task RunSequential<T1, T2>(this Func<T1, T2, Task> del, T1 param1, T2 param2)
{
foreach (var d in del.GetInvocationList().OfType<Func<T1, T2, Task>>())
{
await d(param1, param2);
}
}
// Additional methods for more parameters go here
}
您似乎确实在尝试以非预期的方式使用委托。他们实际上不应该控制顺序或让功能相互依赖来完成。
制作自定义集合可能更好,如果您想要一些类似委托的行为,可以覆盖 += 和 -= 。
你的问题的原因是你的代表有一组不同的参数。
解决方案是创建一个额外的委托,其中包含包含参数的调用,类似于 System.Windows.Forms.MethodInvoker delegate。
您的 methodInvoker 的唯一区别是您的 methodInvoker 不是 returns 无效的委托,而是 returns 任务的委托。
您的扩展程序 class 中的函数与您的 foreach 类似:
public delegate task MethodInvoker();
static class DelegateExtensions
{
public static async Task ExecuteDelegates(this IEnumerable<MethodInvoker> methodInvokers)
{
foreach (var methodInvoker in methodInvokers)
{
await methodInvoker();
}
}
}
用法如下:
public MyClass
{
private async Task F1()
{
Debug.WriteLine("Begin F1");
await Task.Delay(TimeSpan.FromSeconds(1));
Debug.WriteLine("F1 Completed");
}
private async Task F2(TimeSpan waitTime)
{
Debug.WriteLine("Begin F2");
await Task.Delay(waitTime);
Debug.WriteLine("F2 Completed");
}
private async Task F3(int count, TimeSpan waitTime)
{
Debug.WriteLine("Begin F3");
for (int i = 0; i < count; ++i)
{
await Task.Delay(waitTime);
}
Debug.WriteLine("F3 Completed");
}
}
public async Task ExecuteMyFunctions()
{
MyClass X = new MyClass();
IEnumerable<MethodInvoker> myMethodInvokers = new MethodInvoker[]
{
() => X.F1(),
() => X.F2(TimeSpan.FromSeconds(1)),
() => X.F3(4, TimeSpan.FromSeconds(0.25)),
}
await myMethodInvokers.ExecuteDelegates();
}