Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/meteor/3.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#_Asp.net Mvc_Design Patterns_Async Await_Abstract Factory - Fatal编程技术网

C# 为抽象工厂模式组合异步和非异步实现

C# 为抽象工厂模式组合异步和非异步实现,c#,asp.net-mvc,design-patterns,async-await,abstract-factory,C#,Asp.net Mvc,Design Patterns,Async Await,Abstract Factory,我们的在线商店有一个ASP.NETMVC应用程序。用户必须从多种付款方式中进行选择才能购买物品。为此,我们实现了一个抽象工厂模式: public interface IPaymentServiceFactory { IPaymentService GetPaymentService(PaymentServiceEnum paymentServiceType); } public interface IPaymentService { PaymentSettingsModel Ge

我们的在线商店有一个ASP.NETMVC应用程序。用户必须从多种付款方式中进行选择才能购买物品。为此,我们实现了一个抽象工厂模式:

public interface IPaymentServiceFactory
{
    IPaymentService GetPaymentService(PaymentServiceEnum paymentServiceType);
}
public interface IPaymentService
{
    PaymentSettingsModel GetPaymentSettingsModel();
}
在我们的行动中使用:

public ActionResult ProcessCart(PaymentDataModel paymentData)
{
    var paymentService = _paymentServiceFactory.GetPaymentService(paymentData.PaymentServiceType);
    var paymentSettings = paymentService.GetPaymentSettingsModel();
}
当我们了解到某些支付方法需要内部异步调用时,就会出现问题。例如,第三方在线支付服务方法必须通过http异步调用,以便在其一侧创建支付对象。实施:

    public class OnlinePaymentService : IPaymentService
    {
        private readonly IOnlinePaymentServiceApiClient _client;
        public async Task<PaymentSettingsModel> GetPaymentSettings()
        {
            var result =  await _client.CreatePaymentAsync();
            return result;
        }
    }
公共类OnlinePaymentService:IPaymentService
{
专用只读IOnlinePaymentServiceApiClient\u客户端;
公共异步任务GetPaymentSettings()
{
var result=await_client.CreatePaymentAsync();
返回结果;
}
}
所以我们提出了一个问题:如何处理不同支付方式的异步和同步场景。我们决定让一切都异步。更新代码:

public interface IPaymentService
{
    Task<PaymentSettingsModel> GetPaymentSettings();
}
public async Task<ActionResult> ProcessCart(PaymentDataModel paymentData)
{
    var paymentService = _paymentServiceFactory.GetPaymentService(paymentData.PaymentServiceType);
    var paymentSettings = await paymentService.GetPaymentSettingsModel();
}
公共接口IPaymentService
{
任务GetPaymentSettings();
}
公共异步任务。
有没有办法避免这种后果?在特定情况下使用Task.Run真的很糟糕吗

在特定情况下使用Task.Run真的很糟糕吗

是的,主要是因为这不必要地使事情复杂化了

您可以使用
task.FromResult
返回结果为给定值的已完成任务

这是完全同步的:

public class CashPaymentService : IPaymentService
{
    public Task<PaymentSettingsModel> GetPaymentSettings()
    {
        return Task.FromResult( new PaymentSettingsModel() );
    }
}
公共类现金支付服务:IPaymentService
{
公共任务GetPaymentSettings()
{
返回Task.FromResult(new PaymentSettingsModel());
}
}

请注意,此处缺少
async
——这是可能的,因为它是一个实现细节,而不是
IPaymentService

定义的一部分。幸运的是,您不能将
async
放在一个接口中开始。非常感谢。Task.FromResult完成了任务!使用
Task.Run
add的复杂性是什么?我找不到任何,这实际上是创建异步包装器的标准机制之一。我在这里看到的唯一问题是
Task.Run
将提供一个额外的线程,但异步操作将确保在后台进行操作时释放上下文检查代码并比较
任务。运行
任务。从结果
任务完成源
。如果操作是长时间运行的,则
Task.Run
是提供非阻塞实现的唯一选项,其余两个都将阻塞,因为
Task.FromResult
的目的是返回硬编码/固定值,
TaskCompletionSource
是异步事件包装,它们都不适用于用例您发布了我引用的同一篇文章,它只是告诉您如何不使用
Task.Run
,但也建议如何使用
Task.Run
进行异步包装。最后,它只是警告不要在方法内部使用它,由于这是ASP.Net应用程序的一个问题,不创建假异步方法,而是从调用程序本身包装它,
按钮单击文章中的
。@MrinalKamboj在我的例子中是CashPaymentService.GetPaymentSettings()不是长时间运行的操作。没有必要提高它。所以对我来说,在这样的情况下跑步真是太过分了。此外,从面向对象的角度来看,我不想更改CashPaymentService实现中的哪怕是一行代码,因为当前的功能只是关于引入新的支付方法。@MrinalKamboj从您的评论中,我无法理解的另一件事是关于用Task.Run包装方法。对于mvc应用程序和我的场景,我别无选择,只能将Task.Run放在CashPaymentService中。没有别的地方可以放它了。您在GetPaymentSettingsTR方法中为我所做的只是将Task.Run放入方法中,这正是您要避免的。您所做的是正确的,这也是Stephen Cleary建议的,他反对的是,不要放入
Task.Run
放入
new PaymentSettingsModel()
constructor或创建一个伪异步,因为这会让人困惑,但从调用方包装起来很好。到目前为止,构造函数调用几乎是硬编码的值,甚至
Task.FromResult
TaskCompletionSource
都可以工作,但是如果引入延迟(如我所示),那么您将只会发现
Task.Run
是非阻塞调用,rest all将阻塞
public class CashPaymentService : IPaymentService
{
    public Task<PaymentSettingsModel> GetPaymentSettings()
    {
        return Task.FromResult( new PaymentSettingsModel() );
    }
}