C# 在生成器模式中使用异步任务
我目前使用builder模式构建MVC视图模型C# 在生成器模式中使用异步任务,c#,.net,asynchronous,async-await,builder,C#,.net,Asynchronous,Async Await,Builder,我目前使用builder模式构建MVC视图模型 var viewModel = builder .WithCarousel(), .WithFeaturedItems(3), .Build() 我遇到的问题是,当我必须对异步方法进行服务调用时。这意味着我的生成器方法必须返回Task,而不是HomeViewModelBuilder。这防止我链接构建方法,因为我必须等待它们 示例方法 pub
var viewModel = builder
.WithCarousel(),
.WithFeaturedItems(3),
.Build()
我遇到的问题是,当我必须对异步方法进行服务调用时。这意味着我的生成器方法必须返回Task
,而不是HomeViewModelBuilder
。这防止我链接构建方法,因为我必须等待它们
示例方法
public async Task<HomeViewModelBuilder> WithCarousel()
{
var carouselItems = await _service.GetAsync();
_viewModel.Carousel = carouselItems;
return this;
}
有没有人在构建器模式中使用过异步方法?如果是这样,是否可以链接方法或将
wait
延迟到build方法。使用builder模式,您可以创建构建对象的策略。在调用build方法之前,它不会构造对象。如果填充对象的逻辑在build方法中,那么可以一起调用所有异步方法
请参见下面构建器的示例代码。这只是一个概念的演示,因此您可能希望对其进行改进
public class Builder
{
private bool hasCarousel = false;
private int featuredItems = 0;
public Builder WithCarousel()
{
hasCarousel = true;
return this;
}
public Builder WithFeaturedItems(int featured)
{
featuredItems = featured;
return this;
}
public BuiltObject Build()
{
if (hasCarousel)
{
// do carousel related calls
}
if (featuredItems > 0)
{
// do featured items related calls.
}
// build and return the actual object.
}
}
异步的处理方法是它具有连锁反应。它倾向于在代码中传播,以使其保持异步 如果您想允许构建器模式(或任何其他流畅模式,如
LINQ
)同时保持其async
,则需要为每个可能的调用设置async
重载。否则,您将无法使用它们,或者将错误地使用它们(例如)
async await
是一个相当新的东西,但我相信随着时间的推移,几乎任何东西都会有一个异步选项。正如我在评论中所说的,您可以为HomeViewModelBuilder
以及任务
编写扩展方法并链接它
public static class HomeViewModelBuilderExtension
{
public static Task<HomeViewModelBuilder> WithCarousel(this HomeViewModelBuilder antecedent)
{
return WithCarousel(Task.FromResult(antecedent));
}
public static async Task<HomeViewModelBuilder> WithCarousel(this Task<HomeViewModelBuilder> antecedent)
{
var builder = await antecedent;
var carouselItems = await builder.Service.GetAsync();
builder.ViewModel.Carousel = carouselItems;
return builder;
}
public static Task<HomeViewModelBuilder> WithFeaturedItems(this HomeViewModelBuilder antecedent, int number)
{
return WithFeaturedItems(Task.FromResult(antecedent), number);
}
public static async Task<HomeViewModelBuilder> WithFeaturedItems(this Task<HomeViewModelBuilder> antecedent, int number)
{
var builder = await antecedent;
builder.ViewModel.FeaturedItems = number;
return builder;
}
}
我以前并没有这样做过,但这里有一个替代Sriram的解决方案 其思想是在builder对象中捕获任务,而不是任务的结果。然后,
Build
方法等待它们完成并返回构造的对象
public sealed class HomeViewModelBuilder
{
// Example async
private Task<Carousel> _carouselTask = Task.FromResult<Carousel>(null);
public HomeViewModelBuilder WithCarousel()
{
_carouselTask = _service.GetAsync();
return this;
}
// Example sync
private int _featuredItems;
public HomeViewModelBuilder WithFeaturedItems(int featuredItems)
{
_featuredItems = featuredItems;
return this;
}
public async Task<HomeViewModel> BuildAsync()
{
return new HomeViewModel(await _carouselTask, _featuredItems);
}
}
此生成器模式适用于任意数量的异步或同步方法,例如:
public sealed class HomeViewModelBuilder
{
private Task<Carousel> _carouselTask = Task.FromResult<Carousel>(null);
public HomeViewModelBuilder WithCarousel()
{
_carouselTask = _service.GetAsync();
return this;
}
private Task<int> _featuredItemsTask;
public HomeViewModelBuilder WithFeaturedItems(int featuredItems)
{
_featuredItemsTask = _featuredService.GetAsync(featuredItems);
return this;
}
public async Task<HomeViewModel> BuildAsync()
{
return new HomeViewModel(await _carouselTask, await _featuredItemsTask);
}
}
公共密封类HomeViewModelBuilder
{
私有任务_carouselTask=Task.FromResult(null);
带有旋转木马()的公共HomeViewModelBuilder
{
_carouselTask=_service.GetAsync();
归还这个;
}
私有任务_featuredItemTask;
带有featuredItems(int featuredItems)的公共HomeViewModelBuilder
{
_featuredItemsTask=\u featuredService.GetAsync(featuredItems);
归还这个;
}
公共异步任务BuildAsync()
{
返回新的HomeViewModel(Wait _carouselTask,Wait _FeaturedItemTask);
}
}
用法仍然相同。公认的答案非常有用,但我认为在某些情况下(至少在我的情况下),等待构建器本身而不是构建对象更有用:
public sealed class HomeViewModelBuilder
{
private List<Task<HomeViewModelBuilder>> taskList= new List<Task<HomeViewModelBuilder>>();
public HomeViewModelBuilder WithCarousel(){
taskList.add(WithCarouselInternal());
return this;
}
private async Task<HomeViewModelBuilder> WithCarouselInternal()
{
var result = await _service.GetAsync();
// do something with the result
return this;
}
public HomeViewModelBuilder WithSomthingElse(){
taskList.add(WithSomethingElseInternal());
return this;
}
(...)
public async Task<HomeViewModel> BuildAsync()
{
await Task.WhenAll(taskList);
// On that point we can now be sure that all builds are finished
return new HomeViewModel(...);
}
}
公共密封类HomeViewModelBuilder
{
私有列表taskList=新列表();
带有旋转木马()的公共HomeViewModelBuilder{
添加(使用carouselinternal());
归还这个;
}
带CarouseLinternal()的专用异步任务
{
var result=await_service.GetAsync();
//对结果做点什么
归还这个;
}
带有Somthingelse()的公共HomeViewModelBuilder{
添加(使用somethingelseinternal());
归还这个;
}
(...)
公共异步任务BuildAsync()
{
等待任务。WhenAll(任务列表);
//在这一点上,我们现在可以确保所有构建都已完成
返回新的HomeViewModel(…);
}
}
我希望这是一种更通用的方法,因为您只需使任务列表保持最新,还可以以简单的方式多次调用同一个构建方法(您不能覆盖以前对构建方法的调用,因为所有的任务都将出现在列表中,因此构建肯定会等待任务完成)?为
任务编写扩展方法
?这样您就可以链接它了?您可以将异步方法调用重新定位到Build()
方法吗?因此,With…()
只修改生成器的状态,记住它需要调用方法。谢谢@SriramSakthivel,我理解这个概念,但不确定实现。你能详细说明一下吗?恐怕没有足够的信息说明你在这些方法中做了什么。发布一些完整的示例,演示该实现的功能。然后我会尝试一下。谢谢,问题在于我选择了什么构建方法。我可能不需要异步方法。请参阅上面编辑的示例代码。然后,您可以先在build方法中调用异步方法,然后再调用其他需要执行的操作。Builder
构造函数应该是一个异步Build
方法吗?@ColinBacon为什么会有问题?您可以使Build()
返回一个任务
,但当您不需要异步执行任何操作时,任务
将已经完成(您可以使用async
-等待
轻松实现)。谢谢svick,您在代码示例中发现了一个错误。当构建方法被认为是类上的构建方法时,它被声明为类的构造函数。我已经更新了。谢谢。请详细说明您需要使用select答案为每个可能的调用设置一个异步重载,我觉得这个答案与此无关。“一路异步”只意味着从请求到响应应该是异步的,甚至这也是有争议的。根据我的经验,这真正意味着选择你的方法并坚持下去。从a点到z点,尽量不要混合使用synch和asych方法。这并不意味着构建器上的所有构建方法都需要是asyc;这是荒谬的。正如所选择的答案所示,您所做的只是使用同步方法来启动任务,然后构建就是打开结果的过程,这仍然是异步的精神,感谢解决方案
var viewModel = await builder
.WithCarousel(),
.WithFeaturedItems(3),
.BuildAsync();
public sealed class HomeViewModelBuilder
{
private Task<Carousel> _carouselTask = Task.FromResult<Carousel>(null);
public HomeViewModelBuilder WithCarousel()
{
_carouselTask = _service.GetAsync();
return this;
}
private Task<int> _featuredItemsTask;
public HomeViewModelBuilder WithFeaturedItems(int featuredItems)
{
_featuredItemsTask = _featuredService.GetAsync(featuredItems);
return this;
}
public async Task<HomeViewModel> BuildAsync()
{
return new HomeViewModel(await _carouselTask, await _featuredItemsTask);
}
}
public sealed class HomeViewModelBuilder
{
private List<Task<HomeViewModelBuilder>> taskList= new List<Task<HomeViewModelBuilder>>();
public HomeViewModelBuilder WithCarousel(){
taskList.add(WithCarouselInternal());
return this;
}
private async Task<HomeViewModelBuilder> WithCarouselInternal()
{
var result = await _service.GetAsync();
// do something with the result
return this;
}
public HomeViewModelBuilder WithSomthingElse(){
taskList.add(WithSomethingElseInternal());
return this;
}
(...)
public async Task<HomeViewModel> BuildAsync()
{
await Task.WhenAll(taskList);
// On that point we can now be sure that all builds are finished
return new HomeViewModel(...);
}
}