事件触发时完成任务

时间:2021-02-02 10:59:53

标签: c# task continuations

这应该很简单,但我就是无法聚焦。

在这种方法中

public static async Task<string> UnloadAsync(Assembly assy, bool silentFail = false)
{
  if (AssyLoadContext.__alcd.ContainsKey(assy))
  {
    var assemblyName = __namd.Where(kvp => kvp.Value == assy).First().Key;
    __alcd[assy].Unloading += alc => //signal the task to complete and return assemblyName
    __namd.Remove(assemblyName);
    __alcd[assy].Unload();
    __alcd.Remove(assy);
    Debug.WriteLine($"Unloaded assembly '{assy.GetName().Name}'");
  }
  if (silentFail) 
  {
    return null;
  }
  else
  {
    throw new InvalidOperationException($"Assembly '{assy.GetName().Name}' cannot be unloaded. Did you load it using AssyLoadContext.LoadWithPrivateContext(string assyPath)?");
  }
}

AssemblyLoadContext.Unload() 操作实际上是异步的,但不可等待。一旦不再有强 GC 引用等操作完成,程序集就会卸载并触发 Unloading 事件。

返回值在 assemblyName 中,我想提供给延续。

我可以找到所有关于需要 await 的废话,因为这是产生收益的地方,但我不能那样写。如果没有 await,您如何做到这一点?

1 个答案:

答案 0 :(得分:5)

您正在寻找TaskCompletionSource<string>

public static Task<string> UnloadAsync(Assembly assy, bool silentFail = false)
{
  if (AssyLoadContext.__alcd.ContainsKey(assy))
  {
    var tcs = new TaskCompletionSource<string>();
    var assemblyName = __namd.Where(kvp => kvp.Value == assy).First().Key;
    __alcd[assy].Unloading += alc => tcs.SetResult(assemblyName);
    __namd.Remove(assemblyName);
    __alcd[assy].Unload();
    __alcd.Remove(assy);
    Debug.WriteLine($"Unloaded assembly '{assy.GetName().Name}'");
    return tcs.Task;
  }
  if (silentFail)
  {
    return Task.FromResult<string>(null);
  }

  throw new InvalidOperationException($"Assembly '{assy.GetName().Name}' cannot be unloaded. Did you load it using AssyLoadContext.LoadWithPrivateContext(string assyPath)?");
  }
}

注意,如果这抛出一个 InvalidOperationException,它会在调用 UnloadAsync 时被抛出,而不是被包裹在返回的 Task 中(如果你的方法是 { {1}})。如果你想改变这个,你可以使用 TaskCompletionSource:

async

或者使用 public static Task<string> UnloadAsync(Assembly assy, bool silentFail = false) { var tcs = new TaskCompletionSource<string>(); if (AssyLoadContext.__alcd.ContainsKey(assy)) { var assemblyName = __namd.Where(kvp => kvp.Value == assy).First().Key; __alcd[assy].Unloading += alc => tcs.SetResult(assemblyName); __namd.Remove(assemblyName); __alcd[assy].Unload(); __alcd.Remove(assy); Debug.WriteLine($"Unloaded assembly '{assy.GetName().Name}'"); } else if (silentFail) { tcs.SetResult(null); } else { tcs.SetException(throw new InvalidOperationException($"Assembly '{assy.GetName().Name}' cannot be unloaded. Did you load it using AssyLoadContext.LoadWithPrivateContext(string assyPath)?")); } return tcs.Task; } 方法:

async