我有Operation
类,比如...
public sealed class Operation
{
public void DoSomething1(ArgType1 arg) {...}
public void DoSomething2(ArgType2 arg) {...}
...
public Task<bool> Execute() {...}
}
DoSomething
方法包要完成,存储arg参数,然后Execute()
方法将启动Task
以原子方式一起完成这项工作。 DoSomething
s的主要影响是副作用,但其中一些也有意义返回一个值,我的第一直觉是返回Task
,如下所示......
public Task<ResultType3> DoSomething3(ArgType3 arg) {...}
但问题是,Task
不会“活着”。因为大多数任务都被认为是。 await
Task
的结果只有在Execute()
被召唤开始工作之前才会毫无结果,因此我觉得这会让消费者感到困惑。好像DoSomething3()
和Execute()
的返回值是非独立的任务。
我可以将Task<>
包含在一个名为Result<>
的新类型中,在内部它会保留Task<>
,而Operation
会保留在TaskCompletionSource<>
上Result
1}}并在Execute()
的末尾设置await
,以便客户在Task
之后Execute
返回Result
后,可以观察{ {1}}。
public Result<T>
{
internal Result(Task t) { _t = t; }
public bool IsComplete { get { return _t.IsComplete; } }
public T Result { get { return _t.Result; } }
// Perhaps more methods delegating to the underlying Task
}
public Result<ResultType4> DoSomething4(ArgType4 arg) {...}
包装Task
的主要动机是与消费者沟通DoSomething3()
的结果不是实时Task
并且难以/不可能致电......
var result = await op.DoSomething4(x);
因为这可能会导致代码死锁,因为还没有人解雇Operation
。请注意此Result<>
类型与Nullable<>
具有不同语义的相似性。
另一种方法是该方法返回一些不透明的对象,该对象将用作在Operation
完成后从Execute()
检索实际结果的键...
var token = op.DoSomething4(x);
...
var succeeded = await op.Execute();
if (! succeeded) return;
var result = op.RetrieveResult(token);
其中,检索结果的签名类似于......
public T RetrieveResult(Token<T> token) {...}
我想另一种选择是添加一个额外的参数作为回调,在实际结果可用时在Execute()
结束时执行...
public void DoSomething5(ArcType5 arg, Func<ResultType5,Task> callback) {...}
因此,你可以看到我有几个不同的选择,没有强烈的直觉,哪个是最合适的。不幸的是,这可能主要只是一个品味问题,但我会很感激对不同方法的反馈。
答案 0 :(得分:2)
我找不到一个理由让你有不同的方法只设置值(而不是那个问题的属性)和一个运行一切的方法。
但是如果你想保留这个设计,你可以做一些非常类似于TPL Dataflow的块。拥有Completion
任务属性,该属性仅在Execute
完成且DoSomething3
无效时才会完成。这使用户可以理解可以等待整个操作(包括Execute
),而不仅仅是DoSomething3
。
public sealed class Operation
{
private TaskCompletionSource<bool> _tcs
public Task Completion {get { return _tcs.Task;} }
public void DoSomething3(ArgType2 arg) {...}
...
public Task<bool> Execute()
{
// ...
_tcs.SetResult(false);
}
}
用法:
operation.DoSomething3(arg);
await operation.Completion;