Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在生成器模式中使用异步任务_C#_.net_Asynchronous_Async Await_Builder - Fatal编程技术网

C# 在生成器模式中使用异步任务

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

我目前使用builder模式构建MVC视图模型

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(...);
  }
}