C# C语言中的命令模式和异步操作处理#
我想听听关于使用命令模式处理异步操作的最佳方法的意见。假设我们有以下示例:C# C语言中的命令模式和异步操作处理#,c#,design-patterns,asynchronous,C#,Design Patterns,Asynchronous,我想听听关于使用命令模式处理异步操作的最佳方法的意见。假设我们有以下示例: 公共类MyCommand { //设置接收器并执行任何操作 public void Execute() { _myReceiver.DoSomething(); } } 问题是:MyCommand不知道MyReceiver.DoSomething()是否有代码的异步部分。如果我想在MyCommand执行后将其推入撤消堆栈,我无法保证其接收器操作已完全执行,因此无法确定MyCommand是否达到可以撤消的状态 我个
公共类MyCommand
{
//设置接收器并执行任何操作
public void Execute()
{
_myReceiver.DoSomething();
}
}
问题是:MyCommand不知道MyReceiver.DoSomething()是否有代码的异步部分。如果我想在MyCommand执行后将其推入撤消堆栈,我无法保证其接收器操作已完全执行,因此无法确定MyCommand是否达到可以撤消的状态
我个人想到了以下解决方案:
公共类MyCommand
{
公共MyCommand(MyReceiver)
{
_myReceiver=接收器;
_myReceiver.DoSomethingFinished+=()=>this.EndExecute();
}
公共无效开始执行()
{
此.EnterExecutionState();
_myReceiver.DoSomething();
}
公共无效EndExecute()
{
此.LeaveExecutionState();
}
//国家处理相关事务
}
我现在有办法确保命令的接收器已经完成了执行任何操作,并且可以将其推入撤销堆栈。然而,对每一个包含异步操作的接收者类进行事件垃圾邮件处理确实让我感到很烦
我还没有在互联网上找到太多关于这个话题的信息,我希望听到不同的方法
OBS:使命令管理所有异步相关代码不是一个选项:)。首先,我将添加到方法的名称
Async
,以明确地向您的命令
类使用者发出该方法以异步方式执行的信号
其次,我将添加一个like参数Action
,该参数将在方法异步调用完成时调用。因此,当异步操作终止时,可以通知此方法调用方
编辑
obj.DoSomethingAsync(…参数,完成操作)
类似的内容
public interface ICommand
{
void Execute();
event EventHandler Finished;
}
public class MyCommand : ICommand
{
public MyCommand(MyReceiver receiver)
{
_myReceiver = receiver;
_myReceiver.DoSomethingFinished += () => Finished(); // dont forget null check here.
}
public void Execute()
{
_myReceiver.DoSomething();
}
public event EventHandler Finished;
}
这样,该命令的用户就可以注册到Finished事件中,这样它就知道该命令何时完成了它的异步行为,并可以相应地进行操作
或者如果您不想使用事件,那么回调呢
public class MyCommand : ICommand
{
public MyCommand(MyReceiver receiver)
{
_myReceiver = receiver;
}
public void Execute()
{
_myReceiver.DoSomething(() => Finished()); // dont forget null check here.
}
public event EventHandler Finished;
}
无论哪种方式,MyReceiver都只需要有一种方式来通知其调用者它已经完成了。没有办法绕过它。如果要强制要求在控件返回到
Execute
方法之前完成所有处理,而不修改调用代码的行为,则可以修改操作的执行方式
首先初始化所有异步调用,并阻止(等待)当前线程上的调用返回。我不确定异步调用的性质是什么,比如它们位于您知道的线程中,或者将在任意线程上返回,但是您应该能够针对您的问题提出某种线程同步
尝试使用阻止当前线程(在调用异步方法之后),并在所有异步方法返回响应后释放信号量。这将产生“重新同步”异步调用的效果
您可以使用另一种同步方法,但信号量非常简单,可以理解。我认为您在一个类中处理的事情太多了。我会这样分解它:
// An immutable command, to be handled in-process.
// ICommand is a marker interface with no members.
public class DoSomething : ICommand
{
public readonly Id;
public DoSomething(Guid id)
{
Id = id;
}
}
// To be handled out-of-process.
[AsynchronousCommand]
public class DoSomethingThatTakesAReallyLongTime : ICommand
{
public readonly Id;
public DoSomethingThatTakesAReallyLongTime(Guid id)
{
Id = id;
}
}
// This guy could take any number of dependencies: ISomethingRepository, DbContext, etc.
// Doesn't matter, but it's probably gonna have dependencies.
public class DoSomethingHandler : IHandler<DoSomething>
{
public void Handle(DoSomething command) // IHandler<T>'s only member
{
// CRUD or call call a domain method
}
}
public class CommandService : ICommandService
{
public void Execute(params ICommand[] commands) // ICommandService's only member
{
foreach(var command in commands)
{
var handler = GetHandler(command); // Could use your IOC container.
if (HasAsyncAttribute())
new Action(() => handler.Handle(command)).BeginInvoke(null, null);
else
handler.Handle(command);
}
}
}
// Something that might consume these
public class SomethingController
{
private readonly ICommandService _commandService;
public SomethingController(ICommandService commandService)
{
_commandService = commandService;
}
[HttpPost]
public void DoSomething(Guid id)
{
_commandService.Execute(new DoSomething(id));
}
[HttpPost]
public void DoSomethingThatTakesAReallyLongTime(Guid id)
{
_commandService.Execute(new DoSomethingThatTakesAReallyLongTime(id));
}
}
//一个不可变的命令,要在进程中处理。
//ICommand是一个没有成员的标记接口。
公共类DoSomething:ICommand
{
公共只读Id;
公共剂量测量(Guid id)
{
Id=Id;
}
}
//在程序外处理。
[异步命令]
公共类做了一些需要很长时间的事情:ICommand
{
公共只读Id;
公共dosomethingthatakearlylongtime(Guid id)
{
Id=Id;
}
}
//这家伙可以接受任意数量的依赖项:ISomethingRepository、DbContext等。
//没关系,但可能会有依赖关系。
公共类DoSomethingHandler:IHandler
{
public void Handle(DoSomething命令)//IHandler的唯一成员
{
//CRUD或调用域方法
}
}
公共类命令服务:ICommandService
{
public void Execute(params ICommand[]命令)//ICommandService的唯一成员
{
foreach(命令中的var命令)
{
var handler=GetHandler(command);//可以使用IOC容器。
if(HasAsyncAttribute())
新操作(()=>handler.Handle(command)).BeginInvoke(null,null);
其他的
Handle.Handle(命令);
}
}
}
//可能会消耗这些能量的东西
公共类SomethingController
{
私有只读ICommandService _commandService;
公共SomethingController(ICommandService命令服务)
{
_commandService=commandService;
}
[HttpPost]
公共void DoSomething(Guid id)
{
_commandService.Execute(新的DoSomething(id));
}
[HttpPost]
public void dosomethingthatakearlylongtime(Guid id)
{
_Execute(新的dosomethingthatakearallylongtime(id));
}
}
这里最大的优点是,您可以将命令分发给客户端,而无需显式地拖拽处理程序附带的所有依赖项。客户端不应该知道处理程序。客户机需要知道的只是它发送了一个命令,所有命令都应该假定成功。你怎么能说你不知道是否_myReceiver.DoSomething();具有一些异步属性。它要么完成,让你知道