Seb*_*edl 18 .net c# asynchronous .net-core
我有一种情况,我有一个特殊工厂创建的对象树.这有点类似于DI容器,但并不完全相同.
对象的创建总是通过构造函数发生,并且对象是不可变的.
在给定的执行中可能不需要对象树的某些部分,应该懒惰地创建.因此构造函数参数应该只是按需创建的工厂.这看起来像是一份工作Lazy.
但是,对象创建可能需要访问慢资源,因此始终是异步的.(对象工厂的创建函数返回一个Task.)这意味着该创建函数Lazy需要是异步的,因此注入的类型需要Lazy<Task<Foo>>.
但我宁愿没有双层包装.我想知道是否有可能强迫一个Task懒惰,即创建一个Task保证在等待之前不执行的东西.据我所知,a Task.Run或者Task.Factory.StartNew可以随时开始执行(例如,如果来自池的线程是空闲的),即使没有什么可以等待它.
public class SomePart
{
// Factory should create OtherPart immediately, but SlowPart
// creation should not run until and unless someone actually
// awaits the task.
public SomePart(OtherPart eagerPart, Task<SlowPart> lazyPart)
{
EagerPart = eagerPart;
LazyPart = lazyPart;
}
public OtherPart EagerPart {get;}
public Task<SlowPart> LazyPart {get;}
}
Run Code Online (Sandbox Code Playgroud)
Max*_*Max 21
我不确定你为什么要避免使用Lazy<Task<>>,它,但如果它只是为了保持API更容易使用,因为这是一个属性,你可以用一个支持字段来做:
public class SomePart
{
private readonly Lazy<Task<SlowPart>> _lazyPart;
public SomePart(OtherPart eagerPart, Func<Task<SlowPart>> lazyPartFactory)
{
_lazyPart = new Lazy<Task<SlowPart>>(lazyPartFactory);
EagerPart = eagerPart;
}
OtherPart EagerPart { get; }
Task<SlowPart> LazyPart => _lazyPart.Value;
}
Run Code Online (Sandbox Code Playgroud)
这样,用法就好像它只是一个任务,但初始化是懒惰的,只有在需要时才会产生工作.
@Max 的回答很好,但我想添加建立在评论中提到的 Stephen Toub 文章之上的版本:
public class SomePart: Lazy<Task<SlowPart>>
{
public SomePart(OtherPart eagerPart, Func<Task<SlowPart>> lazyPartFactory)
: base(() => Task.Run(lazyPartFactory))
{
EagerPart = eagerPart;
}
public OtherPart EagerPart { get; }
public TaskAwaiter<SlowPart> GetAwaiter() => Value.GetAwaiter();
}
Run Code Online (Sandbox Code Playgroud)
SomePart 显式继承自,Lazy<Task<>>因此很明显它是惰性和异步的。
如果该工厂在真正的异步部分之前需要一些 CPU 繁重的工作,则调用基本构造函数包装lazyPartFactory以Task.Run避免长块。如果不是你的情况,只需将其更改为base(lazyPartFactory)
SlowPart 可通过 TaskAwaiter 访问。所以 SomePart 的公共接口是:
var eagerValue = somePart.EagerPart;var slowValue = await somePart;| 归档时间: |
|
| 查看次数: |
6395 次 |
| 最近记录: |