我正在尝试创建一个具有事件并且可以等待的类,但始终遇到绊脚石。
首先,我尝试了一个TransferJob
类,该类返回一个TransferTask
对象,该对象在返回时已经在运行。这将通过以下方式完成:
public abstract class TransferJob
{
public TransferTask Start()
{
return Start(CancellationToken.None);
}
public TransferTask Start(CancellationToken token)
{
TransferTask task = CreateTransferTask();
task.Start(token);
return task;
}
protected abstract TransferTask CreateTransferTask();
}
public abstract class TransferTask
{
public event EventHandler<TransferStatusChangedEventArgs> StatusChanged;
private Task transferTask;
private TransferStatus status;
public TransferStatus Status
{
get { return this.status; }
protected set
{
TransferStatus oldStatus = this.status;
this.status = value;
OnStatusChanged(new TransferStatusChangedEventArgs(oldStatus, value));
}
}
internal void Start(CancellationToken token)
{
this.transferTask = TransferAsync(cancellationToken);
}
protected abstract Task TransferAsync(CancellationToken cancellationToken);
protected virtual void OnStatusChanged(TransferStatusChangedEventArgs txStatusArgs)
{
if (this.StatusChanged != null)
{
this.StatusChanged(this, txStatusArgs);
}
}
public TaskAwaiter GetAwaiter()
{
return this.transferTask.GetAwaiter();
}
}
上面的问题是,如果TransferTask非常快速地完成,那么TransferJob.Start()的用户可能没有时间在完成之前在返回的TransferTask的StatusChanged事件上注册其事件处理程序。因此,我尝试了另一种方法,即用户必须自己调用TransferTask的Start()方法。这将使用户有时间在
TransferTask
调用和transferJob.CreateTask()
调用之间在transferTask.Start()
上注册其事件处理程序:public abstract class TransferJob
{
public abstract TransferTask CreateTask();
}
public abstract class TransferTask
{
public event EventHandler<TransferStatusChangedEventArgs> StatusChanged;
private Task transferTask;
private TransferStatus status;
public TransferStatus Status
{
get { return this.status; }
protected set
{
TransferStatus oldStatus = this.status;
this.status = value;
OnStatusChanged(new TransferStatusChangedEventArgs(oldStatus, value));
}
}
public void Start(CancellationToken token)
{
this.transferTask = TransferAsync(cancellationToken);
}
protected abstract Task TransferAsync(CancellationToken cancellationToken);
protected virtual void OnStatusChanged(TransferStatusChangedEventArgs txStatusArgs)
{
if (this.StatusChanged != null)
{
this.StatusChanged(this, txStatusArgs);
}
}
public TaskAwaiter GetAwaiter()
{
return this.transferTask.GetAwaiter();
}
}
现在,我有另一个问题。如果用户在调用
await transferTask;
之前尝试使用transferTask.Start();
,则可能会因为未启动任务(因此将其分配给NullReferenceException
字段)而抛出transferTask
。我真的在努力解决这个问题。有办法吗?还是使用比以上更好的模式? 最佳答案
我真的不相信这是个好主意。只需公开TAP模式。删除事件以及transferTask
。 Start
的调用者必须保留该任务,并将其传递给要侦听完成的任何代码。这样就产生了非常干净的API。没有易变的状态,非常容易理解,支持所有用例。
如果坚持的话,您可以创建一个看起来像真实的代理任务:
public abstract class TransferTask
{
public event EventHandler<TransferStatusChangedEventArgs> StatusChanged;
private TaskCompletionSource<object> transferTask = new ...; //changed
private TransferStatus status;
public TransferStatus Status
{
get { return this.status; }
protected set
{
TransferStatus oldStatus = this.status;
this.status = value;
OnStatusChanged(new TransferStatusChangedEventArgs(oldStatus, value));
}
}
public Task Start(CancellationToken token)
{
await TransferAsync(cancellationToken);
transferTask.SetResult(null); //complete proxy task
}
protected abstract Task TransferAsync(CancellationToken cancellationToken);
protected virtual void OnStatusChanged(TransferStatusChangedEventArgs txStatusArgs)
{
if (this.StatusChanged != null)
{
this.StatusChanged(this, txStatusArgs);
}
}
public TaskAwaiter GetAwaiter()
{
return this.transferTask.Task.GetAwaiter(); //changed
}
}
现在,
transferTask.Task
始终不为null。该任务最终将完成。我很快将其归为一体,希望这个想法很明确。可能您应该将事件基于
transferTask.Task.ContinueWith(...)
。关于c# - 在同一个类上启用EAP和异步/等待,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31436445/